text:
using SCS
using Base.Test

# Solve a trivial problem
A = reshape([1.0],(1,1))
solution = SCS_solve(1, 1, A, [1.0], [1.0], 1, 0, [0], 0, [0], 0, 0, 0; linearsolver=SCS.Indirect);
@assert solution.ret_val == 1

# Solve the same problem from the low-level interface
function low_level_scs_indirect()
    A = reshape([1.0],(1,1))
    data = create_scs_data(1, 1, A, [1.0], [1.0])
    cone = create_scs_cone(1, 0, [0], 0, [0], 0, 0, 0, Float64[], 0)

    p_work, info = SCS_init(SCS.Indirect, data, cone)
    status, solution, info, p_work = SCS_solve(SCS.Indirect, p_work, data, cone, info)

    @test status == 1
    SCS_finish(SCS.Indirect, p_work)
end

low_level_scs_indirect();

# Random, feasible conic problem (no exponential or SDP cones)
# Problem data taken from https://github.com/cvxgrp/scs/blob/master/examples/raw/demo_data
function feasible_basic_conic_indirect()
    n = 11;
    m = 112;

    f = 0;
    l = 100;
    qsize = 1;
    ssize = 0;
    ep = 0
    ed = 0
    q = [12]
    s = Int[]

    b = [1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 1.000000000000000000 0.500000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 0.000000000000000000 -0.500000000000000000]';
    c = [-3.687045235791087894 -3.143065318037093103 2.289111017442006180 1.817854752120232842 1.515395029041534336 -0.621501577833336483 0.896216656096898490 -0.946791055758523736 1.016669273321816114 -0.487162812452204275 1.000000000000000000]';

    colptr = vec([0 101 202 303 404 505 606 707 808 909 1010 1012]');
    rowval = vec([0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 101 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 102 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 103 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 104 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 105 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 106 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 107 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 108 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 109 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 110 100 111]');
    values = [0.267905121455780493 -0.267905121455780493 1.027917777157112633 -1.027917777157112633 -2.297179456574058865 2.297179456574058865 -0.236264446681208273 0.236264446681208273 -1.867877520107915412 1.867877520107915412 0.162954278135808150 -0.162954278135808150 0.235147192773076164 -0.235147192773076164 0.683684798830484719 -0.683684798830484719 0.392483177863985011 -0.392483177863985011 0.924930282229331158 -0.924930282229331158 -2.159603434889884266 2.159603434889884266 0.032954349530355143 -0.032954349530355143 -1.102218022704213984 1.102218022704213984 1.089305235192274290 -1.089305235192274290 -0.205884695396086725 0.205884695396086725 0.662421406463353013 -0.662421406463353013 0.693092774331567685 -0.693092774331567685 -0.477841384181042939 0.477841384181042939 1.491230998886413417 -1.491230998886413417 0.967521567131197524 -0.967521567131197524 2.911450906122811766 -2.911450906122811766 -0.458525517948777994 0.458525517948777994 1.523410490461409861 -1.523410490461409861 -0.005653356349895766 0.005653356349895766 -0.850527244660144954 0.850527244660144954 -0.914427729368161080 0.914427729368161080 -0.366414500628216067 0.366414500628216067 0.845776230367680237 -0.845776230367680237 -2.167303234827925085 2.167303234827925085 -0.311201875432801589 0.311201875432801589 -1.343057018434765437 1.343057018434765437 0.329227476201254532 -0.329227476201254532 0.937892636329581530 -0.937892636329581530 -1.292149283676578220 1.292149283676578220 0.727475864828183827 -0.727475864828183827 -0.865828722236433812 0.865828722236433812 -0.712336606310262854 0.712336606310262854 -1.416761181304521111 1.416761181304521111 0.065959446153038476 -0.065959446153038476 0.538493444004808364 -0.538493444004808364 -0.117595299877949297 0.117595299877949297 -0.280761797896251886 0.280761797896251886 -0.375803478543587532 0.375803478543587532 0.359440188545873895 -0.359440188545873895 0.102984464805364467 -0.102984464805364467 0.677264337807959915 -0.677264337807959915 1.688890914825171841 -1.688890914825171841 1.415133737581891982 -1.415133737581891982 -0.260722295562210549 0.260722295562210549 0.105168432618356816 -0.105168432618356816 -1.000000000000000000 1.889555946293464350 -1.889555946293464350 -0.360701715826208469 0.360701715826208469 -0.791169413590648185 0.791169413590648185 -0.750549444160155899 0.750549444160155899 -0.607358855980370871 0.607358855980370871 -0.277021092833852400 0.277021092833852400 -0.203825835441055647 0.203825835441055647 -0.090812111090438824 0.090812111090438824 0.840648343850716073 -0.840648343850716073 2.366017834555732335 -2.366017834555732335 0.311512251535443596 -0.311512251535443596 1.294136754697726044 -1.294136754697726044 1.721966354400402466 -1.721966354400402466 -0.394704235668438097 0.394704235668438097 -0.866913724584800427 0.866913724584800427 -0.521584096752930937 0.521584096752930937 -1.603058260481896147 1.603058260481896147 1.131290495226984216 -1.131290495226984216 -0.025983716418195180 0.025983716418195180 1.032351087100518372 -1.032351087100518372 -2.224637786217645186 2.224637786217645186 -0.162734496391128941 0.162734496391128941 0.273673555167950888 -0.273673555167950888 -2.459010134987294371 2.459010134987294371 -0.918195490875242326 0.918195490875242326 3.349596084069234259 -3.349596084069234259 0.687195476960778762 -0.687195476960778762 -1.052718851466527328 1.052718851466527328 0.050624437594229355 -0.050624437594229355 0.918266891203016855 -0.918266891203016855 -0.402689924407274802 0.402689924407274802 0.172930030148746722 -0.172930030148746722 -0.729742764543249600 0.729742764543249600 -1.328294149765913312 1.328294149765913312 0.074352549621726965 -0.074352549621726965 0.382668985189349498 -0.382668985189349498 1.390238993188259498 -1.390238993188259498 -0.729630799636320049 0.729630799636320049 -1.335330064808758044 1.335330064808758044 1.080203042138974112 -1.080203042138974112 0.614815150749306483 -0.614815150749306483 0.948846205447098190 -0.948846205447098190 0.537516306246460296 -0.537516306246460296 0.518670152004236606 -0.518670152004236606 0.322774153261093044 -0.322774153261093044 -0.078317251196179785 0.078317251196179785 -0.638547209457334453 0.638547209457334453 -0.310091732599216852 0.310091732599216852 -1.401041709751936981 1.401041709751936981 0.444484264649852523 -0.444484264649852523 -1.000000000000000000 -0.822571831606042192 0.822571831606042192 1.149442322385366033 -1.149442322385366033 0.691743212128930307 -0.691743212128930307 -0.724535264426504177 0.724535264426504177 -0.770046062316186330 0.770046062316186330 -1.007402320427817077 1.007402320427817077 -0.866896266710699970 0.866896266710699970 0.157127863727930334 -0.157127863727930334 -0.683933911229745561 0.683933911229745561 0.083157607370303074 -0.083157607370303074 -0.035297284818969786 0.035297284818969786 1.595145009715114970 -1.595145009715114970 0.406340236572520330 -0.406340236572520330 0.313725728340701338 -0.313725728340701338 1.802698956145747822 -1.802698956145747822 0.913926791275037065 -0.913926791275037065 -1.724161676159960077 1.724161676159960077 1.110418687944275673 -1.110418687944275673 0.461906200032139447 -0.461906200032139447 -1.098377187481418327 1.098377187481418327 0.561283369614635874 -0.561283369614635874 -1.440822605093403652 1.440822605093403652 0.982226376107772414 -0.982226376107772414 0.143410505344264055 -0.143410505344264055 0.190094441263810476 -0.190094441263810476 -0.674859862131981347 0.674859862131981347 0.361191784792336323 -0.361191784792336323 0.855409038211248252 -0.855409038211248252 0.247664495777954352 -0.247664495777954352 -2.624827919838180978 2.624827919838180978 -0.292697699274345136 0.292697699274345136 1.816454414571746945 -1.816454414571746945 -1.762366799993794864 1.762366799993794864 -0.242523030834476544 0.242523030834476544 -0.116759392895071146 0.116759392895071146 -1.459080445461180098 1.459080445461180098 0.418859403675993669 -0.418859403675993669 0.182519919352751275 -0.182519919352751275 0.317673288988851388 -0.317673288988851388 0.894501008979574186 -0.894501008979574186 0.240779273237376745 -0.240779273237376745 1.063124478382744265 -1.063124478382744265 -0.182203074499369566 0.182203074499369566 0.335540465956989664 -0.335540465956989664 0.679568586001081942 -0.679568586001081942 -0.630620458948692009 0.630620458948692009 -0.528865322760086354 0.528865322760086354 0.629959392835118481 -0.629959392835118481 -0.609885742617505167 0.609885742617505167 1.774739631265793260 -1.774739631265793260 -1.000000000000000000 0.506497876068581654 -0.506497876068581654 0.000326691662373364 -0.000326691662373364 1.543000152238471312 -1.543000152238471312 -0.187951520155494600 0.187951520155494600 -0.466908966395864100 0.466908966395864100 -2.168190935795662355 2.168190935795662355 0.568204320157958742 -0.568204320157958742 1.162818994214767310 -1.162818994214767310 0.219565016076267133 -0.219565016076267133 0.846238367236053057 -0.846238367236053057 0.444152474144777987 -0.444152474144777987 0.432732607599171037 -0.432732607599171037 1.350501505879705411 -1.350501505879705411 -0.796531305332793926 0.796531305332793926 -1.500064621977569068 1.500064621977569068 0.013262735417032061 -0.013262735417032061 -0.919545740399544842 0.919545740399544842 -0.720599621073430674 0.720599621073430674 0.169023573624101114 -0.169023573624101114 -0.415746346580660175 0.415746346580660175 1.447138808881193173 -1.447138808881193173 1.260731770052782030 -1.260731770052782030 -0.226090396655164727 0.226090396655164727 0.412205318621164107 -0.412205318621164107 0.147480060602125151 -0.147480060602125151 0.273383713767828274 -0.273383713767828274 -0.356808074324790336 0.356808074324790336 1.013981805928862112 -1.013981805928862112 0.269343540845133511 -0.269343540845133511 -0.131014546908719692 0.131014546908719692 1.346897709728866133 -1.346897709728866133 -1.077804826671031835 1.077804826671031835 -2.166977323932548494 2.166977323932548494 4.082665741988060759 -4.082665741988060759 -0.158050142170322011 0.158050142170322011 0.826308257196147311 -0.826308257196147311 1.364531401616584372 -1.364531401616584372 0.447820002980886034 -0.447820002980886034 -0.800383328883453427 0.800383328883453427 0.638742958438863195 -0.638742958438863195 1.284767930527563218 -1.284767930527563218 -1.777775442492336433 1.777775442492336433 -0.479920638682654332 0.479920638682654332 -0.000486121785261532 0.000486121785261532 0.915943372086077567 -0.915943372086077567 0.281169314576583562 -0.281169314576583562 -0.240045850376803122 0.240045850376803122 0.678876421485956394 -0.678876421485956394 -0.308976088076634348 0.308976088076634348 0.798465100342247380 -0.798465100342247380 -1.000000000000000000 1.087159846595101786 -1.087159846595101786 -2.099121773424734716 2.099121773424734716 0.955342180681646336 -0.955342180681646336 0.805784538992392330 -0.805784538992392330 0.372022079078506707 -0.372022079078506707 0.131125010573828527 -0.131125010573828527 -0.428233847101695153 0.428233847101695153 0.239263979475934280 -0.239263979475934280 0.495824604297952665 -0.495824604297952665 -1.974307955242914581 1.974307955242914581 1.603706793378771422 -1.603706793378771422 0.009079468662080679 -0.009079468662080679 -0.340801415852529821 0.340801415852529821 -0.040371866286134914 0.040371866286134914 1.252279885978765384 -1.252279885978765384 -0.480496637097164170 0.480496637097164170 0.025086653875817752 -0.025086653875817752 1.133441378387318510 -1.133441378387318510 1.685216101290169188 -1.685216101290169188 -0.377749910040516390 0.377749910040516390 -0.885742663004153163 0.885742663004153163 -0.763260238467797114 0.763260238467797114 -2.779910894557495293 2.779910894557495293 -0.639811141540734374 0.639811141540734374 0.187441762332883177 -0.187441762332883177 -0.284330518550652722 0.284330518550652722 -0.822012436267475666 0.822012436267475666 -1.334746162474092834 1.334746162474092834 -0.669135345166555928 0.669135345166555928 2.095458091555622460 -2.095458091555622460 -1.489693812460274769 1.489693812460274769 -1.445874828327142092 1.445874828327142092 0.885203250913691675 -0.885203250913691675 -0.130365900983153593 0.130365900983153593 -1.227811794109990418 1.227811794109990418 1.887461183070288540 -1.887461183070288540 -0.372231541771805063 0.372231541771805063 0.854005807614880763 -0.854005807614880763 0.233301251116458497 -0.233301251116458497 0.128510580408158021 -0.128510580408158021 0.317037146153163529 -0.317037146153163529 -0.072474722564739330 0.072474722564739330 -0.902410880592201314 0.902410880592201314 -0.135741998878747605 0.135741998878747605 -0.191584542689922477 0.191584542689922477 -0.691971672385520598 0.691971672385520598 -0.740985851503054516 0.740985851503054516 0.777878742705346071 -0.777878742705346071 2.316421323974115154 -2.316421323974115154 0.442592141778819392 -0.442592141778819392 -1.000000000000000000 0.057300638002260783 -0.057300638002260783 -0.765880201091782453 0.765880201091782453 0.018658948070564667 -0.018658948070564667 -0.884852857487954947 0.884852857487954947 -0.119099061784913321 0.119099061784913321 0.110823913892580964 -0.110823913892580964 -0.628128807378484644 0.628128807378484644 -0.958779880814327745 0.958779880814327745 0.335534085713524222 -0.335534085713524222 -1.589119342626025944 1.589119342626025944 -0.339290158527664643 0.339290158527664643 0.683350252109244716 -0.683350252109244716 -1.341947200350975145 1.341947200350975145 -1.094209818133984768 1.094209818133984768 -1.303705781186516477 1.303705781186516477 0.205495234849035424 -0.205495234849035424 2.150190108595682936 -2.150190108595682936 0.504922856191401204 -0.504922856191401204 0.202643337241746463 -0.202643337241746463 0.368081470693641333 -0.368081470693641333 0.559511763513307891 -0.559511763513307891 0.621090751359941073 -0.621090751359941073 -0.437128202629269713 0.437128202629269713 -0.320080245358165705 0.320080245358165705 0.676285408860144432 -0.676285408860144432 0.294205824825271300 -0.294205824825271300 1.086292218045164404 -1.086292218045164404 0.131665472918444160 -0.131665472918444160 0.913562447586867998 -0.913562447586867998 -0.441621943495057401 0.441621943495057401 0.175143091644549165 -0.175143091644549165 -0.057950142634599001 0.057950142634599001 1.272633458197298228 -1.272633458197298228 -0.739156567900068118 0.739156567900068118 -1.172962844785649050 1.172962844785649050 0.690349067302703512 -0.690349067302703512 1.261164997660849663 -1.261164997660849663 -0.578273293013085943 0.578273293013085943 0.705747556964109291 -0.705747556964109291 1.199347759194084206 -1.199347759194084206 -0.561175893138310178 0.561175893138310178 0.418058667159627584 -0.418058667159627584 0.775233786194539753 -0.775233786194539753 -1.005165576137645900 1.005165576137645900 -0.248095930746197624 0.248095930746197624 0.968389188406472812 -0.968389188406472812 0.052644854909029225 -0.052644854909029225 0.459974856433697621 -0.459974856433697621 -0.764234718892679465 0.764234718892679465 -0.924252504077109682 0.924252504077109682 -1.000000000000000000 -2.285037536291396609 2.285037536291396609 0.330256994776636892 -0.330256994776636892 0.781166851577503984 -0.781166851577503984 1.091855391225416527 -1.091855391225416527 0.303546598398528267 -0.303546598398528267 0.883205583346516998 -0.883205583346516998 -0.200432630370076942 0.200432630370076942 0.103227093467374034 -0.103227093467374034 -0.536598825966995818 0.536598825966995818 -0.114094330489527385 0.114094330489527385 0.352868274327804876 -0.352868274327804876 1.184201821029249313 -1.184201821029249313 -0.281707700532443983 0.281707700532443983 1.299996056001185840 -1.299996056001185840 1.288620739680663041 -1.288620739680663041 -0.124775257491364810 0.124775257491364810 2.676893190719289439 -2.676893190719289439 0.393601576244927809 -0.393601576244927809 -0.860157510975565920 0.860157510975565920 -0.162471839540177465 0.162471839540177465 0.870279361361823600 -0.870279361361823600 -0.150491539662725049 0.150491539662725049 -1.332287989766246072 1.332287989766246072 0.065469192080399141 -0.065469192080399141 -1.317974937874615282 1.317974937874615282 0.509029000143902399 -0.509029000143902399 0.368719922900173025 -0.368719922900173025 0.646131466361322016 -0.646131466361322016 -0.791339007906923575 0.791339007906923575 -0.438686479862148759 0.438686479862148759 1.538459427564934812 -1.538459427564934812 -0.258833298230582876 0.258833298230582876 -1.504378351654444890 1.504378351654444890 -1.036168922551806260 1.036168922551806260 -1.956795979420658416 1.956795979420658416 1.136562859433311701 -1.136562859433311701 -1.534637925681490822 1.534637925681490822 -0.794072741149785766 0.794072741149785766 1.371420904545398223 -1.371420904545398223 0.507731197862471229 -0.507731197862471229 -0.301106820285413468 0.301106820285413468 -1.017488307329072361 1.017488307329072361 -0.614101742707810261 0.614101742707810261 -0.781398901846928728 0.781398901846928728 0.053926155630600305 -0.053926155630600305 -0.528096222539175431 0.528096222539175431 1.913029349947439561 -1.913029349947439561 -0.179790546417506469 0.179790546417506469 -0.683750983213183505 0.683750983213183505 -1.021241699433223404 1.021241699433223404 -1.000000000000000000 -2.049890895857636064 2.049890895857636064 -1.417369090725334679 1.417369090725334679 -0.850006203774544056 0.850006203774544056 0.462163832152883536 -0.462163832152883536 -1.576268635512163341 1.576268635512163341 -1.441553193165409752 1.441553193165409752 0.528158464893624058 -0.528158464893624058 -0.356925550618781839 0.356925550618781839 1.025569158189527652 -1.025569158189527652 0.449741824505590193 -0.449741824505590193 0.832324652288013667 -0.832324652288013667 -1.071955389109310985 1.071955389109310985 -1.634162605612502706 1.634162605612502706 0.505770152619639646 -0.505770152619639646 -0.529050505036871677 0.529050505036871677 2.096511832225588901 -2.096511832225588901 0.761631727644857093 -0.761631727644857093 -1.192983489646781026 1.192983489646781026 2.417357758103033216 -2.417357758103033216 -0.054862528716085407 0.054862528716085407 -0.911480249686436483 0.911480249686436483 -0.754953036467722605 0.754953036467722605 -0.765582251486999321 0.765582251486999321 0.336077875984923224 -0.336077875984923224 0.627961935625664491 -0.627961935625664491 -0.048378255106885454 0.048378255106885454 0.324089280340306485 -0.324089280340306485 0.867067055827554611 -0.867067055827554611 0.482964936776505871 -0.482964936776505871 0.913512419073207127 -0.913512419073207127 -0.986143056174743848 0.986143056174743848 0.106234733647867743 -0.106234733647867743 0.600980235748239666 -0.600980235748239666 -0.586035595820676769 0.586035595820676769 -0.480578250645586014 0.480578250645586014 -1.153384062348248751 1.153384062348248751 -1.171239036967019365 1.171239036967019365 -0.322604826885027784 0.322604826885027784 0.136050508789379743 -0.136050508789379743 1.065246013053737562 -1.065246013053737562 -0.601401671319884090 0.601401671319884090 0.095447184573948712 -0.095447184573948712 2.265102206815573727 -2.265102206815573727 -0.205975175263903992 0.205975175263903992 0.427509540011176081 -0.427509540011176081 0.520441665490702587 -0.520441665490702587 -2.895556119432680209 2.895556119432680209 0.620757007249324810 -0.620757007249324810 -0.005251762123618039 0.005251762123618039 1.083172978556625754 -1.083172978556625754 -1.000000000000000000 0.365201243908861106 -0.365201243908861106 1.250190028804355702 -1.250190028804355702 0.224932134413901919 -0.224932134413901919 -0.902251105448115265 0.902251105448115265 -0.368544518082968842 0.368544518082968842 -0.234274596888654818 0.234274596888654818 -1.199930348307246541 1.199930348307246541 -1.573215897391668561 1.573215897391668561 1.509172423622493930 -1.509172423622493930 -0.092660720516525047 0.092660720516525047 0.436287483119169650 -0.436287483119169650 2.405987267352854619 -2.405987267352854619 0.831037192863362639 -0.831037192863362639 0.142705011000706122 -0.142705011000706122 1.491265436361660868 -1.491265436361660868 0.351484213706070359 -0.351484213706070359 -1.520421211131988359 1.520421211131988359 -0.990651120099914628 0.990651120099914628 0.755067493672610501 -0.755067493672610501 -0.475209396547241036 0.475209396547241036 -1.267282701791565547 1.267282701791565547 0.419704110261967744 -0.419704110261967744 -0.766570120470680960 0.766570120470680960 -1.021465600725925960 1.021465600725925960 -0.521511779651205876 0.521511779651205876 0.374754396256747835 -0.374754396256747835 0.785689533273488006 -0.785689533273488006 -0.158926489386465586 0.158926489386465586 1.132984272112302016 -1.132984272112302016 0.957264734680358442 -0.957264734680358442 -0.404576492822195655 0.404576492822195655 0.589263426043603378 -0.589263426043603378 -1.033631870548684217 1.033631870548684217 0.598534902235807076 -0.598534902235807076 0.919327935687768494 -0.919327935687768494 -0.224031230235764156 0.224031230235764156 -0.611669152956875184 0.611669152956875184 1.482839170994118660 -1.482839170994118660 -0.094214130236777896 0.094214130236777896 -0.902166146440054773 0.902166146440054773 -0.248954946055154891 0.248954946055154891 -3.062190912378776719 3.062190912378776719 -0.941533647749983493 0.941533647749983493 -2.160942710456435822 2.160942710456435822 0.108026826423921113 -0.108026826423921113 2.075626678312805673 -2.075626678312805673 0.873962816238563089 -0.873962816238563089 -0.408815616016248828 0.408815616016248828 -0.129621031340232146 0.129621031340232146 1.406273548026924392 -1.406273548026924392 -1.000000000000000000 -0.915804710938513011 0.915804710938513011 -1.221871953979475789 1.221871953979475789 -0.300753582392023655 0.300753582392023655 0.075403833175464410 -0.075403833175464410 0.131548564249591410 -0.131548564249591410 -0.071935913309509686 0.071935913309509686 0.767128678708612011 -0.767128678708612011 1.191450868677329078 -1.191450868677329078 -1.613612865536336205 1.613612865536336205 -0.441167481116289062 0.441167481116289062 3.280667499979234236 -3.280667499979234236 -1.201795592615207742 1.201795592615207742 2.951958398205375200 -2.951958398205375200 -1.276239289802024945 1.276239289802024945 -1.132028638493809636 1.132028638493809636 2.436513002643889259 -2.436513002643889259 0.068454839838739664 -0.068454839838739664 0.258744697658441825 -0.258744697658441825 0.912475983862615192 -0.912475983862615192 0.079789089547489894 -0.079789089547489894 -0.095257282931539802 0.095257282931539802 0.032098955389624276 -0.032098955389624276 -0.446625802398977478 0.446625802398977478 0.066898135600142933 -0.066898135600142933 0.187007172038859970 -0.187007172038859970 -0.111876955691751587 0.111876955691751587 -1.135249689741995027 1.135249689741995027 0.855383920893877270 -0.855383920893877270 -0.584066032000734703 0.584066032000734703 0.043977907469829255 -0.043977907469829255 -1.235073226970094584 1.235073226970094584 0.903396805744995368 -0.903396805744995368 -1.419367800674472990 1.419367800674472990 -0.669079320858145477 0.669079320858145477 1.846743883979396816 -1.846743883979396816 -0.197864347556086784 0.197864347556086784 0.178086679323349178 -0.178086679323349178 -0.726541129368893035 0.726541129368893035 0.102548417306546763 -0.102548417306546763 0.101435234812034022 -0.101435234812034022 -0.607294919138270162 0.607294919138270162 -0.232543338993652815 0.232543338993652815 1.024873011278554902 -1.024873011278554902 -0.367070741104161269 0.367070741104161269 0.015584587754633259 -0.015584587754633259 0.893352765523915404 -0.893352765523915404 -0.318598602767036110 0.318598602767036110 -0.565309322249061386 0.565309322249061386 -0.869520326873197580 0.869520326873197580 1.087601931698385149 -1.087601931698385149 -1.000000000000000000 -1.000000000000000000 -1.000000000000000000];

    A = SparseMatrixCSC(m, n, colptr + 1, rowval + 1, vec(values))

    sol = SCS_solve(m, n, A, b, c, f, l, q, qsize, s, ssize, ep, ed; linearsolver=SCS.Indirect)
    @test sol.ret_val == 1
end

feasible_basic_conic_indirect();

# Feasible conic problem with exponential cones (no SDP cones)
# Problem data taken from https://github.com/cvxgrp/scs/blob/master/examples/raw/randomConeFeasible
function feasible_exponential_conic_indirect()
    n = 24;
    m = 71;
    f = 10;
    l = 10;
    qsize = 5;
    ssize = 0;
    ep = 10;
    ed = 5;
    q = [0 1 0 2 3]';
    s = Int[];

    b = [-0.883995908378185202 0.247092008779755457 0.000000000000000000 -0.908862166109580594 0.493908919902298627 0.215008446366246719 -0.756619621167477718 -0.244711519515723036 -2.185656700286640941 -1.777454077348217920 1.191220488872941186 -0.072631913036035556 -0.884888299606113149 -3.097264426296667761 -0.491714244502094944 0.820612279439398518 -5.027612089838516596 -0.218768971520485273 -1.779020210515877221 0.000000000000000000 1.049908711514835780 0.423746551400514093 -0.078381703192688112 -0.387520318558316479 0.959884766721948446 -0.080140759738691447 1.300716537987696597 -0.217623259095584554 -0.772345449741623336 -0.014345948596158398 2.002325668310177775 2.019795133016943467 1.285967533112210681 -0.503689333815666940 3.004968290408826626 -1.438380292815098382 -0.801360722211995502 0.731209144814713885 -2.639460367287462361 1.255602400085220394 -0.301008710647552635 0.478491654540030953 -0.984259121708334739 0.276318763804415002 0.631004508865874447 1.808914085971600416 0.379215625232032671 -0.627707287528726510 -1.823589846592805763 0.000000000000000000 0.376255266738256766 0.577717062577191354 1.119478389802739615 0.977520182221270906 0.000000000000000000 3.417141674635829851 -0.093825387556597556 -1.780472058822893722 1.589707484189159858 0.133747881756402398 1.316803247114450848 -0.153152367127352751 -1.712195041092097192 -0.151457896071195447 1.216498217552836492 0.610011299767568738 4.095401319683990238 -0.761957853948331154 -0.485158172250699793 -1.990510613776122817 1.151843011380725867]';
    c = [1.126284961639569149 0.474697659805094763 -2.123033959497108825 4.908405709073863754 1.205680866991396316 -0.305211910012288978 -6.293810724494532494 -0.698794364791622713 2.279737335846038437 -0.945550079347313055 -0.727867522608193762 -1.869349988323733891 -3.748045451887451307 1.125456539838578518 0.750188573436658457 1.255406629974515686 -4.887321053728165055 4.021564105931883404 0.000000000000000000 -5.091850958321861853 -0.068986990722853969 -1.715673120575787136 0.036366854219751360 -3.625427280331933400]';
    colptr = vec([0 7 12 18 24 34 37 43 47 54 59 68 79 87 93 101 111 119 127 128 139 141 150 154 162]');
    rowval = vec([5 17 22 31 55 65 69 12 18 30 34 58 9 11 13 18 30 66 0 10 17 18 44 58 5 6 7 26 29 31 53 57 61 67 39 43 68 3 9 13 14 16 21 7 36 38 55 4 12 21 27 40 46 66 3 26 34 44 53 5 11 17 27 31 37 42 45 63 13 22 24 33 36 40 50 56 58 64 65 6 10 13 16 18 23 41 44 17 31 41 46 55 58 16 20 33 38 42 58 62 64 7 13 18 21 26 36 45 52 56 60 8 15 21 30 33 48 53 64 1 5 11 16 23 24 28 39 37 5 8 28 30 41 55 57 59 61 64 67 56 70 0 3 10 18 22 34 37 42 65 16 25 51 65 5 13 24 28 32 36 40 55]');
    values = [0.155488995903893978 -0.062791225718324961 -0.723631125289072807 -0.238301504589733010 -1.222593380186629552 0.176577794642316321 0.705885019349415832 -1.327043149520291010 -0.054886129988677361 0.595357673884101768 -0.608557444738319409 -0.345065971567320995 0.312023828329273611 0.600142508808629960 0.401844497039814952 -1.118732002452724972 1.046832784305231856 2.003390610862264776 -0.289963040800027938 -0.723121479570418058 -2.021958930051789505 -0.626378538867138679 1.223062551733806957 1.012801864262980134 0.818551368521000522 -0.493009815316450606 0.045841105713705040 0.571247629714476068 -0.131820352915893585 0.229596893220313791 0.245804851893843240 -0.300111005615675885 -0.438141355602143678 -0.432003843727780446 2.787335227813435345 1.778255899291004472 -0.360076301153971601 1.174116751493714972 1.804493771724186901 1.470201280848519421 0.397466995795308642 1.516266896645952711 1.808862620519253950 -0.063783120022332648 0.910482579647111989 0.439952188872439920 0.316500360797716096 -1.481399071578779925 -1.441013597638914456 -1.079866250738828137 0.759568325914783404 -1.854299082689693901 0.066756911436865754 0.950993499549085408 0.126947068043645916 0.412796010311391848 -0.737059771697805455 -1.283256104604766579 0.070045209416807905 -0.292588130834394000 0.593930795648752730 -0.982131525779047831 -0.657201299098350344 0.439997904822629349 0.183703423091249041 0.541334435719376117 0.901931466951714444 -0.297697144009373027 -0.326814228785906158 -0.593250315010803608 -0.373070658631004248 0.601102032468295078 0.867082552947325391 -1.140681144669632330 -0.069214254022048366 -0.418903195029848852 0.629334584931418806 1.143678910770957513 0.970737823554688517 -0.180739356415037467 0.526547037749559022 0.812323004640795987 -0.032566509194480744 0.249517740562795132 0.942133319236942435 -0.433609296474823602 -2.328954516283341825 0.612511298166949270 -0.616865928889227422 -0.168469878275448348 0.035479485837577006 -1.342869236621930140 -0.213015082641054704 1.635999657278292441 -0.640709506726057532 0.092307951238962266 0.101662443700341151 0.389266203843263880 -0.865697308360523721 0.983545235205556256 -0.531620117507069279 0.611335194065235954 0.545540103526115816 -0.993019006549600625 0.199189444075264455 -0.986961883351521907 -0.079892839058037096 -1.835638683735192345 0.235809672576244050 -0.140321722056366061 -0.270068812648098844 0.109317693774870342 -0.751894738681891606 -1.521026561768954677 -0.197958632611841989 1.729841391572364273 2.227168078167871546 -0.608580510079949288 0.972565728008653152 0.475424811707271355 -0.540786416488525767 -2.186021612748235476 -0.425058490610030815 0.300485967595730263 0.815488508092498399 -0.603918481376169214 -1.166665030194641073 0.290790134884453599 -0.308641815280113085 1.814015450280375585 0.176946822329411252 0.327678163907200726 -0.218533560026580531 -1.032184344072171189 1.029365712103099240 -1.043108301337626775 -0.408674314796325655 -0.522250484993548869 0.648940737363586706 0.899822328897223467 1.415849068436585423 1.261550718141148275 -0.656815928948082495 -0.260250861706116776 0.974950224811311550 0.401336339818801069 -1.749879306387625455 0.112944717021051230 0.751228984688332879 -0.413972274974230170 0.589433366718220664 0.120205281956355367 -0.507323064614498387 -0.438270518204901538 -1.096593301525472075 -1.051632309520848407 0.798886992156715880 -0.307503469862750567 0.274836786911666187 0.898475989377141793 -1.093343456239604494 1.331215885064973348];

    A = SparseMatrixCSC(m, n, colptr + 1, rowval + 1, vec(values))

    sol = SCS_solve(m, n, A, b, c, f, l, q, qsize, s, ssize, ep, ed; linearsolver=SCS.Indirect)
    @assert sol.ret_val == 1
end

feasible_exponential_conic_indirect();

# Feasible conic problem with exponential and SDP cones
# BLAS and LAPACK must be linked
# Problem data taken from https://github.com/cvxgrp/scs/blob/master/examples/raw/randomConeFeasibleSDP
function feasible_sdp_conic_indirect()
    n = 15;
    m = 46;
    f = 3;
    l = 3;
    qsize = 3;
    ssize = 3;
    ep = 2;
    ed = 2;
    q = [2 3 4]';
    s = [2 3 4]';
    b = [-0.757244022903780567 0.000000000000000000 -1.892151461056349238 -0.163643541176375057 0.000000000000000000 -1.081834184990333014 0.795686782662209935 -0.459554179861930256 0.000000000000000000 -0.021401100284139062 0.221822131770426145 0.624165617064677769 0.103992209313486683 0.383906342184775817 0.220548856781228653 0.207179552343107032 -0.251552024267611252 -0.940985378402204531 0.143203475268773417 -0.637990380166112425 -0.047725168844638927 -1.400142610548834821 -0.518640886812063995 -0.466344476203716551 -0.306977592331722393 -0.733266642509912470 1.636614964482892454 2.801678431332372821 0.542022232315772401 0.561733632830300200 -2.792150430434448882 0.679252001011406148 0.060935700608246268 1.017184097064012693 -1.472726175247485836 0.298927350489858801 0.283700004781893000 -5.946289176766917706 0.563505302268017871 1.728907659188164914 0.783139219605003434 0.241447041607357943 -0.100769851306178021 -0.312858596637428432 0.715583273231235939 0.030051296196268559]';
    c = [-0.159052113684804763 1.195574970454808206 0.354942838344536771 -0.144003787891437030 0.031108987439201756 -6.024128094309364911 -6.684198760055235056 -2.875770597510225901 -1.958442177032014397 -3.231061172173861795 -0.047201649069278366 -1.907845683517030544 0.605113199091042553 2.360164164701050726 -0.367619298880400125]'
    colptr = vec([0 3 11 18 24 25 30 36 39 44 47 48 51 56 61 66]);
    rowval = vec([7 26 27 3 5 9 15 26 28 31 34 7 12 21 25 32 38 44 10 11 16 35 36 40 10 11 14 24 26 34 11 12 16 20 38 42 13 34 42 3 6 11 15 29 30 34 37 31 2 5 42 11 20 22 24 34 6 17 23 25 44 0 21 30 32 42]);
    values = [-0.067865553542687335 1.530072514424096086 1.603457298120044117 -0.334886938964047698 1.039090653504955997 -0.217606350143191934 0.307061919146703444 -0.249024742513713787 1.234679146890777846 -0.155941035724768945 0.391894209432449070 -0.195221197898754362 0.625190357087625714 -0.532011376808820713 -0.192239517539274762 -0.261163645776478603 -0.457014640871582556 -1.565056014150725039 -0.303107621351740908 0.051290355848774699 0.515246335524848553 -0.320575506600239257 0.012469041361617951 -1.066701398984749583 0.023045624425105282 0.826062790211595455 0.949221831131022542 -0.712004549027422495 -1.064213412889326804 -1.250678906826407477 1.526976686733372723 0.183227263001436963 0.261406324055382666 -0.162337672803827743 1.242448406390738391 0.933728162671238482 -1.029767543566621146 -0.947960922331432032 0.350321001356111605 0.552783345944550142 1.260658709120896281 0.466914435684700035 0.135174942099455658 -0.229626450963180490 -1.506159703979718989 -0.741106093940411492 -3.029177341404145629 0.276068253931536167 -0.848709379933659025 -1.117638683265208099 -0.029005763708726321 -0.209713338388736709 -0.146054634331526184 -0.875729346160017297 -1.174212331456816250 -0.507817550278173657 0.660143141046977688 -0.941485770955433732 -0.483815050110121103 -0.274070229932602216 -0.084539479817724195 0.455029556444334349 1.682103594663178825 -0.444627816446985402 0.443421912904091331 0.182452167505983420];

    A = SparseMatrixCSC(m, n, colptr + 1, rowval + 1, vec(values))

    sol = SCS_solve(m, n, A, b, c, f, l, q, qsize, s, ssize, ep, ed; linearsolver=SCS.Indirect)
    @test sol.ret_val == 1
end

feasible_sdp_conic_indirect();

# Feasible conic problem with power cones
function feasible_pow_conic_indirect()
    n = 9;
    m = 28;
    f = 5;
    l = 5;
    qsize = 0;
    ssize = 0;
    ep = 0;
    ed = 0;
    q = Int[];
    s = Int[];
    psize = 6
    p = [-3.000000e-01 2.500000e-01 7.500000e-01 -4.000000e-01 8.700000e-01 -1.200000e-01]';
    b = [-0.887386390749058451 1.868842541924223610 -0.755288651776904296 0.000000000000000000 0.000000000000000000 0.000000000000000000 -0.242379421582613414 0.000000000000000000 0.000000000000000000 0.000000000000000000 2.000257252427916743 0.841870176542910631 -1.245982120437818974 0.644136460056986104 -0.068037985179701416 0.041769615282582828 1.081088773255733271 1.417941447788496845 0.955133254978043800 2.477002457942629299 0.326964373865085811 0.322926943542406031 0.765172439731569787 1.673745381540497679 0.056224953164704453 0.024308325296160227 -0.492458408194795028 -0.193643481641372683]';
    c = [0.581324380640174887 0.000000000000000000 -1.274914899429569370 1.437959547820705897 0.178499636115030086 -2.834480531039399676 -0.465471220509626749 0.440187271984058437 1.655006387767208542]';
    colptr = vec([0 2 2 8 11 12 15 21 22 25]);
    rowval = vec([11 19 10 11 14 18 19 26 1 19 23 2 1 14 19 0 1 10 14 23 26 16 0 6 18]);
    values = [-0.511172207780700494 -0.557093642241281661 -0.322939921204497105 -0.002041345349432955 1.606510961119237413 -0.070499387778693703 -0.336705699002853465 1.122647857944874650 0.375041023696103593 0.415227462723155749 -2.444298897865559539 -2.377454293765433491 1.125161817875028225 0.847648634500925313 1.557813537123208025 0.400486023191097329 0.728641591773904751 0.317987915650739417 0.268100811901575309 -1.098195387799324019 0.581667258045274083 -0.923489085784077401 -1.341380722378574086 -0.273782415743900387 0.147891351014747152];

    A = SparseMatrixCSC(m, n, colptr + 1, rowval + 1, vec(values))

    sol = SCS_solve(m, n, A, b, c, f, l, q, qsize, s, ssize, ep, ed, p, psize; linearsolver=SCS.Indirect)
    @test sol.ret_val == 1
end

feasible_pow_conic_indirect();


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

using Markdown
using InteractiveUtils

# ╔═╡ 0cde3f18-6b7e-4c96-a09e-b5419d481053
using AbstractPlutoDingetjes, HypertextLiteral, Parameters, PlutoDevMacros, Deno_jll

# ╔═╡ 83e7541d-1646-4071-a29a-45a71453b5d6
@only_in_nb using PlutoUI

# ╔═╡ 5ee4e18c-8a03-41c8-ab2c-2c3ff430f5f8
@only_in_nb PlutoUI.TableOfContents()

# ╔═╡ 652695a3-5c8b-4cea-b79c-fe1192df8527
md"# Ingredients"

# ╔═╡ 01e347d4-a998-476a-a549-bbd591330439
@plutoinclude "./d3_abstractions.jl" "all"

# ╔═╡ 9df4facb-6862-4898-aa04-ae944c94969f
md"# Context"

# ╔═╡ 6fdebb9a-3053-4699-bd3b-6fa4c43c3283
md"## Structure"

# ╔═╡ 82090d2a-bc09-4f5e-8377-3452fdaeca46
begin
	Axis = @NamedTuple{domain::Vector{<:Number}, range::Vector{<:Number}}
	struct Context <: D3Component
		xAxis 	   :: Axis
		yAxis 	   :: Axis
		children   :: Vector{<:D3Component}
		attributes :: D3Attr
		embedX     :: Tuple{Float64, Float64}
		embedY     :: Tuple{Float64, Float64}
		id         :: String
		drawAxis   :: Bool
	end

	# TODO: fix typing
	Context(xAxis, yAxis, children::Vector{<:D3Component}, id; attributes=D3Attr(), embedX=(0.0, 1.0), embedY=(0.0, 1.0), drawAxis=true) =
		Context(xAxis, yAxis, children, attributes, embedX, embedY, id, drawAxis)
end;

# ╔═╡ 4557ccac-50fa-448b-b1a8-10c2196d7083
begin
	Scale(ctx, embedX, embedY, id; attributes=D3Attr()) = Context(ctx.xAxis, ctx.yAxis, [ctx], attributes, embedX, embedY, id, ctx.drawAxis)
end

# ╔═╡ 2d9e6f15-1fb5-4fce-b655-93591e8491bb
Restyle(ctx, attributes, id) = Context(ctx.xAxis, ctx.yAxis, ctx.children, attributes, ctx.embedX, ctx.embedY, id, ctx.drawAxis)

# ╔═╡ 33629ee8-2e0b-44ee-99ba-0b942f3edb0c
RestyleOver(ctx, attributes, id) = Context(ctx.xAxis, ctx.yAxis, [ctx], attributes, ctx.embedX, ctx.embedY, id, ctx.drawAxis)

# ╔═╡ 2bc3ddd7-1a16-4dcc-a029-555697987f17
begin
function Base.extrema(children::Vector{<:D3Component})
	extremas = (Base.extrema).(children)
	minxs = (v -> v.minx).(extremas)
	minys = (v -> v.miny).(extremas)
	maxxs = (v -> v.maxx).(extremas)
	maxys = (v -> v.maxy).(extremas)

	return (
		minx=minimum(minxs),
		miny=minimum(minys),
		maxx=maximum(maxxs),
		maxy=maximum(maxys)
	)
end
end

# ╔═╡ 28c2fbc1-fa21-4ace-86c8-d085f19af466
md"## Javascript Snippet"

# ╔═╡ baa7bf03-77f8-4fa1-9635-df02629cfe01
function Base.show(io::IO, m::MIME"text/javascript", ctx::Context)
show(io, m, @js("""
	context(
		ctx,
		x_scale,
		$(PublishToJS(ctx.xAxis.domain)),
		$(PublishToJS(ctx.embedX)),
		y_scale,
		$(PublishToJS(ctx.yAxis.domain)),
		$(PublishToJS(ctx.embedY)),
		$(PublishToJS(to_named_tuple(ctx.attributes))),
		$(ctx.children),
		$(ctx.id),
		$(ctx.drawAxis)
	)
"""))
end

# ╔═╡ 2b0b5165-776a-4d1f-9151-19465d75124c
Base.show(io::IO, m::MIME"text/html", ctx::Context) =
	show(io, m, @htl("""
	<span id=$(ctx.id)>
	<script id="context-$(ctx.id)">

	const {
		d3,
  		context,
  		context_standalone,
  		area, line, shape,
  		area_standalone, line_standalone, shape_standalone
	} = $(import_local_js(bundle_code));

	const svg = this == null ? DOM.svg($(maximum(ctx.xAxis.range)), $(maximum(ctx.yAxis.range))) : this;
	const s = this == null ? d3.select(svg) : this.s;

	context_standalone(
		s,
		$(PublishToJS(ctx.xAxis.domain)),
		$(PublishToJS(ctx.xAxis.range)),
		$(PublishToJS(ctx.yAxis.domain)),
		$(PublishToJS(ctx.yAxis.range)),
		$(PublishToJS(to_named_tuple(ctx.attributes))),
		$(ctx.children),
		$(ctx.id),
		$(ctx.drawAxis)
	)

	const output = svg
	output.s = s
	return output
	</script>
	</span>
"""))

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150"
Deno_jll = "04572ae6-984a-583e-9378-9577a1c2574d"
HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
PlutoDevMacros = "a0499f29-c39b-4c5c-807c-88074221b949"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
AbstractPlutoDingetjes = "~1.1.4"
Deno_jll = "~1.20.4"
HypertextLiteral = "~0.9.3"
Parameters = "~0.12.3"
PlutoDevMacros = "~0.4.5"
PlutoUI = "~0.7.38"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

julia_version = "1.7.2"
manifest_format = "2.0"

[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.4"

[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[deps.Deno_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "970da1e64a94f13b51c81691c376a1d5a83a0b3c"
uuid = "04572ae6-984a-583e-9378-9577a1c2574d"
version = "1.20.4+0"

[[deps.Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[deps.FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[deps.Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[deps.HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[deps.IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[deps.JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.4.1"

[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.3"

[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[deps.LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[deps.LinearAlgebra]]
deps = ["Libdl", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.9"

[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"

[[deps.OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[deps.Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.3.1"

[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[deps.PlutoDevMacros]]
deps = ["MacroTools", "Requires"]
git-tree-sha1 = "994167def8f46d3be21783a76705228430e29632"
uuid = "a0499f29-c39b-4c5c-807c-88074221b949"
version = "0.4.5"

[[deps.PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "670e559e5c8e191ded66fa9ea89c97f10376bb4c"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.38"

[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "d3538e7f8a790dc8903519090857ef8e1283eecd"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.5"

[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[deps.Random]]
deps = ["SHA", "Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"

[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[deps.SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[deps.Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[deps.UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"

[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
"""

# ╔═╡ Cell order:
# ╟─5ee4e18c-8a03-41c8-ab2c-2c3ff430f5f8
# ╠═83e7541d-1646-4071-a29a-45a71453b5d6
# ╟─652695a3-5c8b-4cea-b79c-fe1192df8527
# ╠═0cde3f18-6b7e-4c96-a09e-b5419d481053
# ╠═01e347d4-a998-476a-a549-bbd591330439
# ╟─9df4facb-6862-4898-aa04-ae944c94969f
# ╟─6fdebb9a-3053-4699-bd3b-6fa4c43c3283
# ╠═82090d2a-bc09-4f5e-8377-3452fdaeca46
# ╠═4557ccac-50fa-448b-b1a8-10c2196d7083
# ╠═2d9e6f15-1fb5-4fce-b655-93591e8491bb
# ╠═33629ee8-2e0b-44ee-99ba-0b942f3edb0c
# ╠═2bc3ddd7-1a16-4dcc-a029-555697987f17
# ╟─28c2fbc1-fa21-4ace-86c8-d085f19af466
# ╠═baa7bf03-77f8-4fa1-9635-df02629cfe01
# ╠═2b0b5165-776a-4d1f-9151-19465d75124c
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

ext: jl


text:
#TODO
# - standarize chemical group notation to make it the same as SAFTgammaMie
# - add a database of group Mw

struct JobackIdealParam <: EoSParam
    Mw::SingleParam{Float64}
    N_a::SingleParam{Int}
    T_c::SingleParam{Float64}
    P_c::SingleParam{Float64}
    V_c::SingleParam{Float64}
    T_b::SingleParam{Float64}
    T_m::SingleParam{Float64}
    H_form::SingleParam{Float64}
    G_form::SingleParam{Float64}
    a::SingleParam{Float64}
    b::SingleParam{Float64}
    c::SingleParam{Float64}
    d::SingleParam{Float64}
    H_fusion::SingleParam{Float64}
    H_vap::SingleParam{Float64}
    eta_a::SingleParam{Float64}
    eta_b::SingleParam{Float64}
end

abstract type JobackIdealModel <: IdealModel end
@newmodelgc JobackIdeal JobackIdealModel JobackIdealParam

export JobackIdeal
function JobackIdeal(components;userlocations=String[], verbose=false)
    groups = GroupParam(components,["ideal/JobackIdeal_Groups.csv"], verbose=verbose)
    params = getparams(groups, ["ideal/JobackIdeal.csv","properties/molarmass_groups.csv"]; userlocations=userlocations, verbose=verbose)
    Mw = params["Mw"]::SingleParam{Float64}
    N_a = params["N_a"]::SingleParam{Int}
    T_c = params["T_c"]::SingleParam{Float64}
    P_c = params["P_c"]::SingleParam{Float64}
    V_c = params["V_c"]::SingleParam{Float64}
    T_b = params["T_b"]::SingleParam{Float64}
    T_m = params["T_m"]::SingleParam{Float64}
    H_form = params["H_form"]::SingleParam{Float64}
    G_form = params["G_form"]::SingleParam{Float64}
    a = params["a"]::SingleParam{Float64}
    b = params["b"]::SingleParam{Float64}
    c = params["c"]::SingleParam{Float64}
    d = params["d"]::SingleParam{Float64}
    H_fusion = params["H_fusion"]::SingleParam{Float64}
    H_vap = params["H_vap"]::SingleParam{Float64}
    eta_a = params["eta_a"]::SingleParam{Float64}
    eta_b = params["eta_b"]::SingleParam{Float64}
    packagedparams = JobackIdealParam(
    Mw,
    N_a,
    T_c,
    P_c,
    V_c,
    T_b,
    T_m,
    H_form,
    G_form,
    a,
    b,
    c,
    d,
    H_fusion,
    H_vap,
    eta_a,
    eta_b)
    references = ["10.1080/00986448708960487"]
    sites = SiteParam(groups.components)
    model = JobackIdeal(packagedparams, groups, sites, BasicIdeal, references=references, verbose=verbose)
    return model
end

function C_p(model::JobackIdeal,T,z=SA[1.0])
    a = model.params.a.values
    b = model.params.b.values
    c = model.params.c.values
    d = model.params.d.values
    n = model.groups.n_flattenedgroups
    res = zero(T+first(z))
    Σz = sum(z)
    @inbounds for i in @comps
        ni = n[i]
        c0 = ∑(a[j]*ni[j] for j in @groups(i)) - 37.93
        c1 = ∑(b[j]*ni[j] for j in @groups(i)) + 0.210
        c2 = ∑(c[j]*ni[j] for j in @groups(i)) - 3.91e-4
        c3 = ∑(d[j]*ni[j] for j in @groups(i)) + 2.06e-7
        pol = (c0,c1,c2,c3)
        res +=z[i]*evalpoly(T,pol)
    end
    return res/Σz
end

function T_b(model::JobackIdeal)
    n = model.groups.n_flattenedgroups
    T_b = model.params.T_b.values
    res = 0.0
    @inbounds begin
        ni = n[1]
        res += ∑(T_b[j]*ni[j] for j in @groups(1))
    end
    res = res + 198.2
end

function T_c(model::JobackIdeal,Tb=T_b(model))
    n = model.groups.n_flattenedgroups
    T_c = model.params.T_c.values
    res = 0.0
    @inbounds begin
        ni = n[1]
        ΣT_ci = ∑(T_c[j]*ni[j] for j in @groups(1))
        res += Tb * (0.584+0.965*ΣT_ci - ΣT_ci^2)^-1
    end
    return res
end

#this style of writing is uglier but faster,
#ideally they should be of the same speed
function V_c(model::JobackIdeal)
    n = model.groups.n_flattenedgroups
    V_c = model.params.V_c.values
    res = 0.0
    groups = @groups(1)
    ni = n[1]
    @inbounds begin
        ΣV_ci = zero(res)
        for idx in 1:length(groups)
            j = groups[idx]
            ΣV_ci +=V_c[j]*ni[j]
        end
        res += 17.5 + ΣV_ci
    end
    #result in mL/mol, converting to m3/mol
    return res*1e-6
end

function P_c(model::JobackIdeal)
    n = model.groups.n_flattenedgroups
    P_c = model.params.P_c.values
    N_a = model.params.N_a.values
    groups = @groups(1)
    ni = n[1]
    @inbounds begin
        ΣP_ci  = 0.0
        ΣN_a = 0
        for idx in 1:length(groups)
            j = groups[idx]
            ΣP_ci += P_c[j]*ni[j]
            ΣN_a += N_a[j]*ni[j]
        end
        res = (0.113 + 0.0032*ΣN_a - ΣP_ci)^-2
    end
    #result in bar, converting to Pa
    return res*100000.0
end

function crit_pure(model::JobackIdeal)
    return (T_c(model),P_c(model),V_c(model))
end

function a_ideal(model::JobackIdealModel, V, T, z)
    a = model.params.a.values
    b = model.params.b.values
    c = model.params.c.values
    d = model.params.d.values
    n = model.groups.n_flattenedgroups
    res = zero(V+T+first(z))
    Σz = sum(z)
    x = z/Σz
    @inbounds for i in @comps
        ni = n[i]
        c0 = ∑(a[j]*ni[j] for j in @groups(i)) - 37.93
        c1 = ∑(b[j]*ni[j] for j in @groups(i)) + 0.210
        c2 = ∑(c[j]*ni[j] for j in @groups(i)) - 3.91e-4
        c3 = ∑(d[j]*ni[j] for j in @groups(i)) + 2.06e-7
        polycoeff = [c0,c1,c2,c3]
        res +=x[i]*(log(z[i]/V) + 1/(R̄*T)*(sum(polycoeff[k]/k*(T^k-298^k) for k in 1:4)) -
        1/R̄*((polycoeff[1]-R̄)*log(T/298)+sum(polycoeff[k]/(k-1)*(T^(k-1)-298^(k-1)) for k in 2:4)))
    end
    return res
end

export JobackIdeal
#acetone = [("acetone",["−CH3"=>1,">C=O (non-ring)"=>1])]


text:
using BiComplex
using Random, Test

Random.seed!(0)

@testset "Bicomplex" begin
@testset "+ - * /" begin
  a = Bicomplex(randn(ComplexF64), randn(ComplexF64))
  unit = Bicomplex(1+0im, 0+0im)
  @test a - a == Bicomplex(0 + 0im, 0 + 0im)
  @test a + a == 2 * a
  @test isapprox(a / a, unit, rtol=10eps(), atol=10eps())
  @test isapprox((a * a) / a / a, unit, rtol=10eps(), atol=10eps())
  @test jm * jm == -unit
  @test jm^2 == -unit
  @test jm / jm == unit
end

@testset "floating point" begin
  z = Bicomplex(randn(ComplexF64, 2)...)
  @test isapprox(1 / (1 / z), z, rtol=0, atol=eps())
end

@testset "exp sin cos log tan" begin
  a = Bicomplex(randn(ComplexF64), randn(ComplexF64))
  unit = Bicomplex(1+0im, 0+0im)
  @test isapprox(sin(a)^2 + cos(a)^2, unit, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(acos(cos(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(cos(acos(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(asin(sin(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(sin(asin(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(tan(atan(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(atan(tan(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(log(exp(a)), a, rtol=sqrt(eps()), atol=10eps())
  @test isapprox(exp(log(a)), a, rtol=sqrt(eps()), atol=10eps())
end

@testset "derivative" begin
  f(x) = sin(x) * exp(-x^2) / x^3
  g(x) = (cos(x) - 2 * x * sin(x) - 3 * sin(x) / x) / x^3 * exp(-x^2)

  for z ∈ (1.0 + im, 1.0 + 0im, 0.0 + im, rand(ComplexF64), -rand(ComplexF64),
           rand(Float64) - im * rand(Float64), -rand(Float64) + im * rand(Float64))
    @test isapprox(BiComplex.derivative(f, z), g(z), rtol=sqrt(eps()), atol=10eps())
    fop(x) = BiComplex._op(f, x)
    @test isapprox(BiComplex.derivative(fop, z), g(z), rtol=sqrt(eps()), atol=10eps())
    @test isapprox(BiComplex.derivative(exp, z), exp(z), rtol=sqrt(eps()), atol=10eps())
    @test isapprox(BiComplex.derivative(cos, z),-sin(z), rtol=2sqrt(eps()),
                   atol=10eps()) # annoyingly needs rtol of 2 sqrt eps
    @test isapprox(BiComplex.derivative(sin, z), cos(z), rtol=sqrt(eps()), atol=10eps())
    @test isapprox(BiComplex.derivative(tan, z), 1/cos(z)^2, rtol=sqrt(eps()), atol=10eps())
    if (1-z^2) != 0
      @test isapprox(BiComplex.derivative(acos, z),-1/sqrt(1-z^2), rtol=sqrt(eps()), atol=10eps())
      @test isapprox(BiComplex.derivative(asin, z), 1/sqrt(1-z^2), rtol=sqrt(eps()), atol=10eps())
    end
    if (1+z^2) != 0
      @test isapprox(BiComplex.derivative(atan, z), 1/(1+z^2), rtol=sqrt(eps()), atol=10eps())
    end
  end
end

@testset "second derivatives" begin
  f(x) = exp(-x^2)
  g(x) = -2 * x * f(x)
  h(x) = -2 * f(x) - 2 * x * g(x)
  for x ∈ (0.0, π / 5, 1e-16, 1e16), s ∈ (-1, 1)
    x *= s
    v, d1, d2 = BiComplex.valuederivatives(f, x)
    @test isapprox(v, f(x), rtol=sqrt(eps()), atol=0)
    @test isapprox(d1, g(x), rtol=sqrt(eps()), atol=0)
    @test isapprox(d2, h(x), rtol=cbrt(eps()), atol=0)
    @test d1 ≈ BiComplex.derivative(f, x)
    @test d2 == BiComplex.secondderivative(f, x)
  end
end

@testset "Promotion conversion, etc" begin
  @test Bicomplex(0.0 + 0im, 1 + 0im) == jm
  @test Bicomplex(0.0 + 0im, 0 + 1im) == jm * im
  @test Bicomplex(0.0 + 1im, 1 + 0im) == jm + im
  @test Bicomplex(0.0 + 1im, 0 + 0im) == im
  @test jm * im == im * jm
  @test (jm * im)^2 == 1
  @test jm^2 == -1
end

end


text:
@testset "run ocal" begin
    r = run_ocal(deepcopy(TEST_PARAMETERS))
    @test length(r[:prediction_global]) == size(TEST_PARAMETERS["data"], 2)
    @test length(r[:prediction_subspaces]) == length(TEST_PARAMETERS["subspaces"])
    @test all(length.(r[:prediction_subspaces]) .== size(TEST_PARAMETERS["data"], 2))
    @test all(length.(r[:score_subspace_grids]) .== size.(TEST_PARAMETERS["subspace_grids"], 2))
    @test length(r[:query_ids]) == 1
    @test length(r[:ranking_subspaces]) == length(TEST_PARAMETERS["subspaces"])
end


text:
using Single
using Base.Test

# custom iterator, that implements nothing except
# bare bones iteration protocol
struct MyRepeater{T}
    t::T
    length::Int
end

Base.start(iter::MyRepeater) = 1
Base.done(iter::MyRepeater, i) = (i > iter.length)
function Base.next(iter::MyRepeater, i)
    iter.t, 2
end

@testset "empty iterators" begin
    iters = [Dict(),
             [],
             (),
             MyRepeater("sad",0),
             Iterators.filter(x -> false, MyRepeater(1,1)),
             zeros(0,0,0)
            ]
    for iter in iters
        @test_throws ArgumentError single(iter)
        default = randn()
        @test single(iter, default) == default
    end
end

@testset "singleton iterators" begin
    iters = [Dict(1 => 2),
             [Float64[]],
             ("hi",),
             MyRepeater("sad",1),
             Iterators.filter(x -> true, MyRepeater(1,1)),
             zeros(1,1,1)
            ]

    for iter in iters
        @test single(iter) == first(iter)
        default = randn()
        @test single(iter, default) == single(iter)

        @inferred single(iter)
        default = first(iter)
        @inferred single(iter, default)
    end
end

@testset "big iterators" begin
    iters = [Dict(1 => 2, 2=>3),
             [[],nothing, ""],
             ("hi", "ho"),
             MyRepeater("sad",10),
             Iterators.filter(x -> true, MyRepeater(1,2)),
             zeros(1,1,2)
            ]
    for iter in iters
        @test_throws ArgumentError single(iter)
        default = randn()
        @test_throws ArgumentError single(iter,default)
    end
end


text:
using Test
using Mimi
using MimiPAGE2009

using MimiPAGE2009: readpagedata, buildpage, initpage, load_parameters, setdistinctparameter

function test_page_model()
    m = Model()

    set_dimension!(m, :time, [2009, 2010, 2020, 2030, 2040, 2050, 2075, 2100, 2150, 2200])
    set_dimension!(m, :region, ["EU", "USA", "OECD", "USSR", "China", "SEAsia", "Africa", "LatAmerica"])

    return m
 end

@testset "MimiPAGE2009.jl" begin

include("test_climatemodel.jl")
include("test_AbatementCosts.jl")
include("test_AdaptationCosts.jl")
include("test_CH4cycle.jl")
include("test_CH4emissions.jl")
include("test_CH4forcing.jl")
include("test_ClimateTemperature.jl")
include("test_CO2cycle.jl")
include("test_CO2emissions.jl")
include("test_CO2forcing.jl")
include("test_Discontinuity.jl")
include("test_EquityWeighting.jl")
include("test_GDP.jl")
include("test_LGcycle.jl")
include("test_LGemissions.jl")
include("test_LGforcing.jl")
include("test_loadparameters.jl")
include("test_mainmodel.jl")
include("test_mainmodel_policyb.jl")
include("test_MarketDamages.jl")
include("test_N2Ocycle.jl")
include("test_N2Oemissions.jl")
include("test_N2Oforcing.jl")
include("test_NonMarketDamages.jl")
include("test_Population.jl")
include("test_SeaLevelRise.jl")
include("test_SLRDamages.jl")
include("test_SulphateForcing.jl")
include("test_TotalAbatementCosts.jl")
include("test_TotalAdaptationCosts.jl")
include("test_TotalCosts.jl")
include("test_TotalForcing.jl")
include("test_mcs.jl")
include("contrib/test_taxeffect.jl")

include("test_standard_api.jl")

end


text:
@doc raw"""
    InvariantMetric{G<:Metric,D<:ActionDirection} <: Metric

Extend a metric on the Lie algebra of an [`AbstractGroupManifold`](@ref) to the whole group
via translation in the specified direction.

Given a group $\mathcal{G}$ and a left- or right group translation map $τ$ on the group, a
metric $g$ is $τ$-invariant if it has the inner product

````math
g_p(X, Y) = g_{τ_q p}((\mathrm{d}τ_q)_p X, (\mathrm{d}τ_q)_p Y),
````

for all $p,q ∈ \mathcal{G}$ and $X,Y ∈ T_p \mathcal{G}$, where $(\mathrm{d}τ_q)_p$ is the
differential of translation by $q$ evaluated at $p$ (see [`translate_diff`](@ref)).

`InvariantMetric` constructs an (assumed) $τ$-invariant metric by extending the inner
product of a metric $h_e$ on the Lie algebra to the whole group:

````math
g_p(X, Y) = h_e((\mathrm{d}τ_p^{-1})_p X, (\mathrm{d}τ_p^{-1})_p Y).
````

!!! warning
    The invariance condition is not checked and must be verified for the entire group.
    To verify the condition for a set of points numerically, use
    [`has_approx_invariant_metric`](@ref).

The convenient aliases [`LeftInvariantMetric`](@ref) and [`RightInvariantMetric`](@ref) are
provided.

# Constructor

    InvariantMetric(metric::Metric, conv::ActionDirection = LeftAction())
"""
struct InvariantMetric{G<:Metric,D<:ActionDirection} <: Metric
    metric::G
end

function InvariantMetric(metric, conv = LeftAction())
    return InvariantMetric{typeof(metric),typeof(conv)}(metric)
end

const LeftInvariantMetric{G} = InvariantMetric{G,LeftAction} where {G<:Metric}

"""
    LeftInvariantMetric(metric::Metric)

Alias for a left-[`InvariantMetric`](@ref).
"""
LeftInvariantMetric(metric) = InvariantMetric{typeof(metric),LeftAction}(metric)

const RightInvariantMetric{G} = InvariantMetric{G,RightAction} where {G<:Metric}

"""
    RightInvariantMetric(metric::Metric)

Alias for a right-[`InvariantMetric`](@ref).
"""
RightInvariantMetric(metric) = InvariantMetric{typeof(metric),RightAction}(metric)

@doc raw"""
    has_approx_invariant_metric(
        G::AbstractGroupManifold,
        p,
        X,
        Y,
        qs::AbstractVector,
        conv::ActionDirection = LeftAction();
        kwargs...,
    ) -> Bool

Check whether the metric on the group $\mathcal{G}$ is (approximately) invariant using a set of predefined
points. Namely, for $p ∈ \mathcal{G}$, $X,Y ∈ T_p \mathcal{G}$, a metric $g$, and a
translation map $τ_q$ in the specified direction, check for each $q ∈ \mathcal{G}$ that the
following condition holds:

````math
g_p(X, Y) ≈ g_{τ_q p}((\mathrm{d}τ_q)_p X, (\mathrm{d}τ_q)_p Y).
````

This is necessary but not sufficient for invariance.

Optionally, `kwargs` passed to `isapprox` may be provided.
"""
has_approx_invariant_metric(
    ::AbstractGroupManifold,
    ::Any,
    ::Any,
    ::Any,
    ::Any,
    ::ActionDirection,
)
@decorator_transparent_function function has_approx_invariant_metric(
    M::AbstractGroupManifold,
    p,
    X,
    Y,
    qs,
    conv::ActionDirection = LeftAction();
    kwargs...,
)
    gpXY = inner(M, p, X, Y)
    for q in qs
        τq = translate(M, q, p, conv)
        dτqX = translate_diff(M, q, p, X, conv)
        dτqY = translate_diff(M, q, p, Y, conv)
        isapprox(gpXY, inner(M, τq, dτqX, dτqY); kwargs...) || return false
    end
    return true
end

direction(::InvariantMetric{G,D}) where {G,D} = D()

function exp!(
    M::MetricManifold{𝔽,<:AbstractGroupManifold,<:InvariantMetric},
    q,
    p,
    X,
) where {𝔽}
    if has_biinvariant_metric(M)
        conv = direction(metric(M))
        return retract!(base_group(M), q, p, X, GroupExponentialRetraction(conv))
    end
    return invoke(exp!, Tuple{MetricManifold,typeof(q),typeof(p),typeof(X)}, M, q, p, X)
end

"""
    biinvariant_metric_dispatch(G::AbstractGroupManifold) -> Val

Return `Val(true)` if the metric on the manifold is bi-invariant, that is, if the metric
is both left- and right-invariant (see [`invariant_metric_dispatch`](@ref)).
"""
function biinvariant_metric_dispatch(M::Manifold)
    return Val(
        invariant_metric_dispatch(M, LeftAction()) === Val(true) &&
        invariant_metric_dispatch(M, RightAction()) === Val(true),
    )
end

has_biinvariant_metric(M::Manifold) = _extract_val(biinvariant_metric_dispatch(M))

@doc raw"""
    invariant_metric_dispatch(G::AbstractGroupManifold, conv::ActionDirection) -> Val

Return `Val(true)` if the metric on the group $\mathcal{G}$ is invariant under translations
by the specified direction, that is, given a group $\mathcal{G}$, a left- or right group
translation map $τ$, and a metric $g_e$ on the Lie algebra, a $τ$-invariant metric at
any point $p ∈ \mathcal{G}$ is defined as a metric with the inner product

````math
g_p(X, Y) = g_{τ_q p}((\mathrm{d}τ_q)_p X, (\mathrm{d}τ_q)_p Y),
````

for $X,Y ∈ T_q \mathcal{G}$ and all $q ∈ \mathcal{G}$, where $(\mathrm{d}τ_q)_p$ is the
differential of translation by $q$ evaluated at $p$ (see [`translate_diff`](@ref)).
"""
invariant_metric_dispatch(::MetricManifold, ::ActionDirection)

@decorator_transparent_signature invariant_metric_dispatch(
    M::AbstractDecoratorManifold,
    conv::ActionDirection,
)
function invariant_metric_dispatch(M::MetricManifold, conv::ActionDirection)
    is_default_metric(M) && return invariant_metric_dispatch(M.manifold, conv)
    return Val(false)
end
function invariant_metric_dispatch(
    M::MetricManifold{𝔽,<:Manifold,<:InvariantMetric},
    conv::ActionDirection,
) where {𝔽}
    direction(metric(M)) === conv && return Val(true)
    return invoke(invariant_metric_dispatch, Tuple{MetricManifold,typeof(conv)}, M, conv)
end
invariant_metric_dispatch(M::Manifold, ::ActionDirection) = Val(false)

function has_invariant_metric(M::Manifold, conv::ActionDirection)
    return _extract_val(invariant_metric_dispatch(M, conv))
end

function inner(M::MetricManifold{𝔽,<:Manifold,<:InvariantMetric}, p, X, Y) where {𝔽}
    imetric = metric(M)
    conv = direction(imetric)
    N = MetricManifold(M.manifold, imetric.metric)
    Xₑ = inverse_translate_diff(M, p, p, X, conv)
    Yₑ = inverse_translate_diff(M, p, p, Y, conv)
    return inner(N, Identity(N, p), Xₑ, Yₑ)
end

function default_metric_dispatch(
    M::MetricManifold{𝔽,<:Manifold,<:InvariantMetric},
) where {𝔽}
    imetric = metric(M)
    N = MetricManifold(M.manifold, imetric.metric)
    default_metric_dispatch(N) === Val(true) || return Val(false)
    return invariant_metric_dispatch(N, direction(imetric))
end

function log!(
    M::MetricManifold{𝔽,<:AbstractGroupManifold,<:InvariantMetric},
    X,
    p,
    q,
) where {𝔽}
    if has_biinvariant_metric(M)
        imetric = metric(M)
        conv = direction(imetric)
        return inverse_retract!(
            base_group(M),
            X,
            p,
            q,
            GroupLogarithmicInverseRetraction(conv),
        )
    end
    return invoke(log!, Tuple{MetricManifold,typeof(X),typeof(p),typeof(q)}, M, X, p, q)
end

function LinearAlgebra.norm(
    M::MetricManifold{𝔽,<:Manifold,<:InvariantMetric},
    p,
    X,
) where {𝔽}
    imetric = metric(M)
    conv = direction(imetric)
    N = MetricManifold(M.manifold, imetric.metric)
    Xₑ = inverse_translate_diff(M, p, p, X, conv)
    return norm(N, Identity(N, p), Xₑ)
end

function Base.show(io::IO, metric::LeftInvariantMetric)
    return print(io, "LeftInvariantMetric($(metric.metric))")
end
function Base.show(io::IO, metric::RightInvariantMetric)
    return print(io, "RightInvariantMetric($(metric.metric))")
end


text:
using Printf

Jstr(J::Rational) = isone(denominator(J)) ? "$(numerator(J))" : "$(numerator(J))/$(denominator(J))"
Jstr(J::Integer) = "$J"
Jstr(J::AbstractString) = J
Jstr(J::AbstractVector) = join(Jstr.(J), ",")

function term_str(term, J)
    i = findfirst(!isnumeric, term)
    mult = i > 1 ? parse(Int, term[1:i-1]) : 0
    isoddterm = term[end] == '*'
    termsym = isoddterm ? term[i:end-1] : term[i:end]

    terms = (i > 1 ? "\$^{$mult}\$$(termsym)" : termsym)*(isoddterm ? "\$^{\\textrm{o}}\$" : "")
    ismissing(J) ? terms : "$(terms)\$_{$(Jstr(J))}\$"
end

function cfg_str(cfg)
    subshells = map(split(cfg, ".")) do s
        if s[1] == '('
            i = findfirst(isequal('<'), s)
            term = strip(isnothing(i) ? s[2:end-1] : s[2:i-1])
            J = isnothing(i) ? missing : strip(s[i+1:end-2])
            "($(term_str(term, J)))"
        else
            i = findlast(!isnumeric, s)
            i < length(s) ? "$(s[1:i])\$^{$(s[i+1:end])}\$" : s
        end
    end
    join(subshells, " ")
end

limit_str(::Missing) = ""

function limit_str(cfg)
    m = match(r"(.*)\((.*)\)", cfg)

    if isnothing(m)
        cfg
    else
        a,b = split(m[2], " ")
        cfgs = cfg_str("$(a).($(b))")
        "$(m[1]) [$(cfg_str(cfgs))]"
    end
end

function latex_table(io::IO, data, name; offset=0u"eV")
    no_offset = iszero(NoUnits(offset/u"eV"))

    write(io, "\\section{$name}\n\\footnotesize\n")
    write(io, "\\tablehead{%\n")
    write(io, "\\textbf{Configuration}&\\textbf{Term}&\\textbf{Energy}")
    no_offset || write(io, "&\\textbf{Offset energy}")
    write(io, "\\\\\n\\hline\n")
    write(io, "}\n")
    write(io, "\\begin{supertabular}{l|l|l$(no_offset ? "" : "|l")}\n")

    cfgs = data[!,1]
    terms = data[!,2]
    Js = data[!,3]
    Es = data[!,4]
    for (cfg,term,J,E) in zip(cfgs,terms,Js,Es)
        Eoff = NoUnits((E + offset)/u"eV")
        ismissing(term) && continue
        if term == "Limit"
            write(io, "\\hline\n")
            write(io, @sprintf("%s & Limit & %08.5f eV", limit_str(cfg), NoUnits(E/u"eV")))
            no_offset || write(io, @sprintf("& %08.5f eV", Eoff))
            write(io, "\\\\\n")
            continue
        end
        write(io, @sprintf("%s & %s & %08.5f eV", cfg_str(cfg), term_str(term,J), NoUnits(E/u"eV")))
            no_offset || write(io, @sprintf("& %08.5f eV", Eoff))
        write(io, "\\\\\n")

    end

    write(io, "\\end{supertabular}\n\n")
end

function latex_table(fun::Function, filename::String)
    open(filename, "w") do file
        write(file, raw"""\documentclass[11pt]{article}
\usepackage[margin=2cm]{geometry}
\usepackage{multicol}
\usepackage{supertabular}
\usepackage{amsmath}
\usepackage{amssymb}
\begin{document}
\twocolumn

""")
        fun(file)
        write(file, "\n\n\\end{document}\n")
    end
end

latex_table(filename::String, data, name; kwargs...) =
    latex_table(file -> latex_table(file, data, name; kwargs...), filename)

export latex_table


text:
# Medatadata getter for documents
metadata(document::D) where D<:AbstractDocument = document.metadata
metadata(crps::C) where C<:Corpus = [doc.metadata for doc in crps]

# Generate utility functions that operate on the DocumentMetadata's fields; these
# are generated dinamically so that adding more methods metadata fields will
# automatically add new methods as well ;)
for fieldname in fieldnames(DocumentMetadata)
    # Create document metadata accessors
    definition = """
        function $(fieldname)(d::AbstractDocument)
            return d.metadata.$(fieldname)
        end
        """
    eval(Meta.parse(definition))
    # Create document metadata setters
    if fieldname != :language
        definition = """
            function $(fieldname)!(d::AbstractDocument, nv::String)
                d.metadata.$(fieldname) = nv
            end
            """
    else
        definition = """
            function $(fieldname)!(d::AbstractDocument, nv::L) where L<:Language
                d.metadata.$(fieldname) = nv
            end
            """
    end
    eval(Meta.parse(definition))
    # Vectorized getters for an entire Corpus
    definition = """
        function $(fieldname)s(c::Corpus)
            map(d->$(fieldname)(d), documents(c))
        end
        """
    eval(Meta.parse(definition))
    # Vectorized setters for an entire Corpus (same value)
    if fieldname in [:author, :timestamp]
        definition = """
            $(fieldname)s!(c::Corpus, nv::String) =
                $(fieldname)!.(documents(c), Ref(nv))
            """
    elseif fieldname == :language
        definition = """
            $(fieldname)s!(c::Corpus, nv::L) where L<:Language =
                $(fieldname)!.(documents(c), Ref(nv))
            """
    else
        definition = """
            $(fieldname)s!(c::Corpus, nv::String) =
                $(fieldname)!.(documents(c), nv)
            """
    end
    eval(Meta.parse(definition))
    # Vectorized setters for an entire Corpus (different values)
    definition = """
        function $(fieldname)s!(c::Corpus, nvs::AbstractVector)
            length(c) == length(nvs) || throw(DimensionMismatch("dimensions must match"))
            for (i, d) in pairs(IndexLinear(), documents(c))
                $(fieldname)!(d, nvs[i])
            end
        end
        """
    eval(Meta.parse(definition))
end


text:
#=
FloydWarshallExample:
- Julia version: 1.6.2
- Author: samuel
- Date: 2021-09-12
=#

using SuiteSparseGraphBLAS
using SparseArrays
using LinearAlgebra
using Test

include("/Users/samuel/Documents/Jupyter/GraphBlasAlgorithmsFinal/src/FloydWarshall.jl")
dim = 5
matrix = GBMatrix(rand(0:100, dim, dim))
@time floydwarshall(matrix, dim)


text:
function AttitudesSequence()
    return AttitudesSequence(())
end

function add_switching_condition(obj::AttitudesSequence, arg0::AttitudeProvider, arg1::AttitudeProvider, arg2::EventDetector, arg3::jboolean, arg4::jboolean, arg5::jdouble, arg6::AngularDerivativesFilter, arg7::AttitudesSequence_SwitchHandler)
    return jcall(obj, "addSwitchingCondition", void, (AttitudeProvider, AttitudeProvider, EventDetector, jboolean, jboolean, jdouble, AngularDerivativesFilter, AttitudesSequence_SwitchHandler), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
end

function get_attitude(obj::AttitudesSequence, arg0::FieldPVCoordinatesProvider, arg1::FieldAbsoluteDate, arg2::Frame)
    return jcall(obj, "getAttitude", FieldAttitude, (FieldPVCoordinatesProvider, FieldAbsoluteDate, Frame), arg0, arg1, arg2)
end

function get_attitude(obj::AttitudesSequence, arg0::PVCoordinatesProvider, arg1::AbsoluteDate, arg2::Frame)
    return jcall(obj, "getAttitude", Attitude, (PVCoordinatesProvider, AbsoluteDate, Frame), arg0, arg1, arg2)
end

function register_switch_events(obj::AttitudesSequence, arg0::Field, arg1::FieldPropagator)
    return jcall(obj, "registerSwitchEvents", void, (Field, FieldPropagator), arg0, arg1)
end

function register_switch_events(obj::AttitudesSequence, arg0::Propagator)
    return jcall(obj, "registerSwitchEvents", void, (Propagator,), arg0)
end

function reset_active_provider(obj::AttitudesSequence, arg0::AttitudeProvider)
    return jcall(obj, "resetActiveProvider", void, (AttitudeProvider,), arg0)
end


text:
struct Simulation
    cells::Vector{Cell} # Vector that holds all the cells in the simulations
    potentials # potential functions
    steptotal::Vector{Int64}
	Simulation(cells::Vector{Cell},potentials) = new(cells,potentials,[0])
end

"""Leapfrog integration step"""
function leapfrog!(s::Simulation, dt)
    terminal_v = (.001 / dt)
    for c in s.cells
        @. c.v2 = c.v + 0.5*dt*c.a

        if abs(c.v2[1]) >= terminal_v
			if c.v2[1] > 0
				c.v2[1] = (terminal_v)
			else
				c.v2[1] = (-terminal_v)
			end
		end
		if abs(c.v2[2]) >= terminal_v
			if c.v2[2] > 0
				c.v2[2] = (terminal_v)
			else
				c.v2[2] = (-terminal_v)
			end
		end
        if c.a == zeros(2)
            c.v2 .= zeros(2)
        end
        @. c.p += dt*c.v2
    end
    return
end

function calcAcceleration!(s::Simulation,ϵ::Float64)
    for i in eachindex(s.cells)
        #for j in eachindex(s.potentials)
        a = sum(s.potentials.(Ref(s.cells[i]),s.cells,ϵ))
        s.cells[i].a .= a
        #end
    end
end

function stepV!(s::Simulation, dt)
    for c in s.cells
	    @. c.v = c.v2 + 0.5*dt*c.a
        if c.a == zeros(2)
            c.v .= zeros(2)
        end
    end
end

function integrate!(s::Simulation, dt, nsteps, ϵ::Float64, μ)
    for i in 1:nsteps
        leapfrog!(s, dt)
        calcAcceleration!(s,ϵ)
        stepV!(s, dt)
        s.steptotal .+= 1
		reproduce!(s, μ)
    end
end

max_stars_repo_name: andi-bergeson/simgym

max_issues_repo_name: andi-bergeson/simgym

max_forks_repo_name: andi-bergeson/simgym


text:
import Knet
using Knet: conv4, pool, mat, KnetArray, zeroone, param, param0, dropout, relu, batchnorm, bnmoments, bnparams, sigm
using HDF5
include("Layers.jl")

moments = [bnmoments(), bnmoments(), bnmoments()]
params = [param(bnparams(64)), param(bnparams(128)), param(bnparams(512))]

ImageEncoder = Chain(Conv(4,4,3,64),BNorm(64,moments[1],params[1],false),Conv(4,4,64,128),BNorm(128,moments[2],params[2],false),Conv(4,4,128,512),BNorm(512,moments[3],params[3],false))

function pool_features(x)
    pooled_features = sum(x, dims=[1,2])
end

obj_detector = Chain(Dense1(512,58))


text:
@def FZ_RR begin #(N, F_yf, F_yr, V, Ax, r)

	# define the lateral tire forces
	F_yf=@F_YF()
	F_yr=@F_YR()
	FZ_rr = zeros(Float64, (length(Ax),1))
	for ii in eachindex(Ax)
		FZ_rr[ii] = 0.5*(FzR0 + KZX*(Ax[ii] - V[ii]*R[ii])) + KZYR*((F_yf[ii] + F_yr[ii])/m)
	end
	FZ_rr
end


text:
export ConstantOperator, IdentityOperator, BasisFunctional

immutable ConstantOperator{T,DS} <: Operator{T}
    λ::T
    space::DS
    ConstantOperator(c::Number,sp::DS) = new(convert(T,c),sp)
    ConstantOperator(L::UniformScaling,sp::DS) = new(convert(T,L.λ),sp)
end

ConstantOperator{T}(::Type{T},c,sp::Space) = ConstantOperator{T,typeof(sp)}(c,sp)
ConstantOperator{T}(::Type{T},c) = ConstantOperator(T,c,UnsetSpace())
ConstantOperator(c::Number,sp::Space) = ConstantOperator(typeof(c),c,sp)
ConstantOperator(c::Number) = ConstantOperator(typeof(c),c)
ConstantOperator(L::UniformScaling) = ConstantOperator(L.λ)
ConstantOperator(L::UniformScaling,sp::Space) = ConstantOperator(L.λ,sp)
IdentityOperator() = ConstantOperator(1.0)
IdentityOperator(S::Space) = ConstantOperator(1.0,S)

for OP in (:domainspace,:rangespace)
    @eval $OP(C::ConstantOperator) = C.space
end

promotedomainspace(C::ConstantOperator,sp::Space) = ConstantOperator(C.λ,sp)

bandinds(T::ConstantOperator) = 0,0

getindex(C::ConstantOperator,k::Integer,j::Integer) =
    k==j?eltype(C)(C.λ):zero(eltype(C))

==(C1::ConstantOperator,C2::ConstantOperator) = C1.λ==C2.λ

function Base.convert{T}(::Type{Operator{T}},C::ConstantOperator)
    if T == eltype(C)
        C
    else
        ConstantOperator{T,typeof(C.space)}(C.λ,C.space)
    end
end

# zero needs to be different since it can take a space to
# a ConstantSpace, in creating functionals
Base.convert{T}(::Type{Operator{T}},x::Number) =
    x==0?ZeroOperator(T,UnsetSpace()):Multiplication(T(x))
Base.convert{T}(::Type{Operator{T}},L::UniformScaling) =
    ConstantOperator(T,L.λ)

Operator(n::Number) = Operator{typeof(n)}(n)
Operator(L::UniformScaling) = Operator{eltype(L)}(L)

## Algebra

for op in (:+,:-,:*)
    @eval ($op)(A::ConstantOperator,B::ConstantOperator) = ConstantOperator($op(A.λ,B.λ))
end

## Basis Functional

immutable BasisFunctional{T} <: Operator{T}
    k::Integer
end

@functional BasisFunctional

BasisFunctional(k) = BasisFunctional{Float64}(k)

bandinds(B::BasisFunctional) = 0,B.k-1
domainspace(B::BasisFunctional) = ℓ⁰

Base.convert{T}(::Type{Operator{T}},B::BasisFunctional) = BasisFunctional{T}(B.k)

Base.getindex{T}(op::BasisFunctional{T},k::Integer) = (k==op.k)?one(T):zero(T)
Base.getindex{T}(op::BasisFunctional{T},k::Range) = convert(Vector{T},k.==op.k)

immutable FillFunctional{T} <: Operator{T}
    λ::T
end

@functional FillFunctional

domainspace(B::FillFunctional) = ℓ⁰

Base.getindex(op::FillFunctional,k::Integer)=op.λ
Base.getindex(op::FillFunctional,k::Range)=fill(op.λ,length(k))

## Zero is a special operator: it makes sense on all spaces, and between all spaces

immutable ZeroOperator{T,S,V} <: Operator{T}
    domainspace::S
    rangespace::V
end

ZeroOperator{T}(::Type{T},d::Space,v::Space) = ZeroOperator{T,typeof(d),typeof(v)}(d,v)
ZeroOperator{T}(::Type{T},d::Space) = ZeroOperator(T,d,ZeroSpace())
ZeroOperator(d::Space,v::Space) = ZeroOperator(Float64,d,v)
ZeroOperator(S::Space) = ZeroOperator(S,ZeroSpace())
ZeroOperator() = ZeroOperator(UnsetSpace(),ZeroSpace())
ZeroOperator{T}(::Type{T}) = ZeroOperator(T,UnsetSpace(),ZeroSpace())

Base.convert{T}(::Type{Operator{T}},Z::ZeroOperator) =
    ZeroOperator(T,Z.domainspace,Z.rangespace)

domainspace(Z::ZeroOperator)=Z.domainspace
rangespace(Z::ZeroOperator)=Z.rangespace

bandinds(T::ZeroOperator)=0,0

getindex(C::ZeroOperator,k::Integer,j::Integer)=zero(eltype(C))

promotedomainspace(Z::ZeroOperator,sp::UnsetSpace) = Z
promoterangespace(Z::ZeroOperator,sp::UnsetSpace) = Z
promotedomainspace(Z::ZeroOperator,sp::Space) = ZeroOperator(sp,rangespace(Z))
promoterangespace(Z::ZeroOperator,sp::Space) = ZeroOperator(domainspace(Z),sp)

isconstop(::Union{ZeroOperator,ConstantOperator})=true
isconstop(S::SpaceOperator)=isconstop(S.op)
isconstop(::)=false

iszeroop(::ZeroOperator) = true
iszeroop(A::ConstantOperator) = A.λ==0.
iszeroop(A) = false

Base.convert{T<:Number}(::Type{T},::ZeroOperator)=zero(T)
Base.convert{T<:Number}(::Type{T},C::ConstantOperator)=convert(T,C.λ)
Base.convert{T<:Number}(::Type{T},S::SpaceOperator)=convert(T,S.op)


text:
"""
    ExactLineSearch{A<:UnivariateAlgorithm, O1, O2}

`ExactLineSearch` computes the optimal step length using univariate methods. Since most
univariate algorithms require repeated calculations of the objective to shrink the bracket
around a local minimum, `ExactLineSearch` is expected to be expensive.

# Fields
- `alg::A`: the univariate algorithm
- `bracket_options::O1`: named tuple of bracketing options
- `alg_options::O2`: named tuple of the univariate algorithm options
"""
struct ExactLineSearch{A<:UnivariateAlgorithm, O1, O2}
    alg::A
    bracket_options::O1
    alg_options::O2
end

"""
    ExactLineSearch(; kwargs...)

Initiate a `ExactLineSearch`. Use keyword arguments to tweak the bracketing phase and the
univariate algorithm.

# Keywords
- `alg::UnivariateAlgorithm`: the univariate algorithm to optimize the step length
- `step=0.01`: bracketing step size
- `scale=2.0`: bracketing scale factor
- `bracket_maxiter::Integer=100`: bracketing maximum number of iterations
- `reltol=1e-6`: relative tolerance
- `abstol=1e-12`: absolute tolerance
- `maxiter::Integer=1_000`: maximum number of iterations
"""
function ExactLineSearch(;
        alg::UnivariateAlgorithm=GoldenSection(),
        step=0.01,
        scale=2.0,
        bracket_maxiter::Integer=100,
        reltol=1e-6,
        abstol=1e-12,
        maxiter::Integer=1_000)
    alg_options = (; reltol, abstol, maxiter)
    bracket_options = (; step, scale, maxiter=bracket_maxiter)
    ExactLineSearch(alg, bracket_options, alg_options)
end

function (els::ExactLineSearch)(f, state, p, α₀)
    ϕ(α) = f(state.x + α * p)
    br = bracket(ϕ, α₀; els.bracket_options...)
    isnothing(br) && error("Initial minimum bracketing failed.")
    lower, upper = br
    solution = optimize(ϕ, lower, upper; els.alg, els.alg_options...)
    solution.converged || error("Exact line search failed.")
    return solution.minimizer
end


text:
"""
abstract type PlasticityRule{S} end

struct PlasticisedChannel{S,S2,A,C<:FlowChannel{S,A},P<:PlasticityRule{S2}} <: FlowChannel{Tuple{S,S2},A}
    channel::C
    modification::P
end

"""

function (p::PlasticisedChannel)(n::Neuron)
    p.modification(p.channel, n)
end

struct OLearyCalcRegulation{T} <: PlasticityRule{Calcium}
    τmRNA::T
    τg::T
    Ca_tgt::T
end

OLeary_reg(ch, τmRNA, τg, Ca_tgt) = PlasticisedChannel(ch, OLearyCalcRegulation(τmRNA, τg, Ca_tgt))::FlowChannel

"""
make new component system from old component system.
- add variables for new sensors, eg, Calcium
- param_to_state substitutes new variables for old parameters in original ch sys
- add extra equations for mRNA and conductance regulation
"""

function (o::OLearyCalcRegulation)(ch::FlowChannel, n::Neuron)
    sys = ch(n)

    (var_conductance,), subst_eqs, _parameters, _defaults, _observed = param_to_state(sys, ch, conductances)

    plast_ch = PlasticisedChannel(ch, o)
    (Ca,) = instantiate_hooks(n, plast_ch, sensed_ions)
    @variables mRNA(t)
    τmRNA, Ca_tgt, τg = get_parameters(o)

    extended_eqs = [D(mRNA) ~ (Ca_tgt - Ca) / τmRNA,
        D(var_conductance) ~ (mRNA - var_conductance) / τg]
    new_eqs = vcat(subst_eqs, extended_eqs)

    new_defaultmap = merge(_defaults, Dict(mRNA => 0.0), default_params(o))

    new_states, new_params = vardivide(Ca, var_conductance, mRNA, τmRNA, Ca_tgt, τg)
    states = [ModelingToolkit.states(sys)..., new_states...]
    parameters = [_parameters..., new_params...]
    plast_sys = ODESystem(new_eqs, t, states, parameters; observed=_observed, defaults=new_defaultmap, name=Symbol(get_name(ch), :_regul))
    return plast_sys
end

function param_to_state(sys, ch, args::Function...)
    _eqs, _states, _parameters, _defaults, _observed = map(
        (equations, states, parameters, ModelingToolkit.get_defaults, observed)) do f
        f(sys)
    end

    (old_conductance,) = map(args) do fun
        getproperty(sys, shorthand_name.(fun(ch))...; namespace=false)
    end
    (var_conductance,) = instantiate_variables(ch, args...)

    # potential bug to fix: only works for a single element of conducts
    _param_indxs = findall(x -> isequal(old_conductance, x), _parameters)

    ## turn conductances into variables
    substitution = Dict(_parameters[_param_indxs]... .=> var_conductance...)
    subst_eqs = [substitute(eq, substitution) for eq in _eqs]

    deleteat!(_parameters, _param_indxs)
    _defaults[var_conductance] = pop!(_defaults, old_conductance)

    return (var_conductance,), subst_eqs, _parameters, _defaults, _observed
end

get_parameters(::OLearyCalcRegulation) = @parameters τmRNA, Ca_tgt, τg
default_params(o::OLearyCalcRegulation) = Dict(get_parameters(o) .=> (o.τmRNA, o.Ca_tgt, o.τg))


text:
using Documenter
using Literate
using Printf
using Tutorials

models_src = joinpath(@__DIR__,"..","models")
models_dst = joinpath(@__DIR__,"src","models")

assets_src = joinpath(@__DIR__,"..","assets")
assets_dst = joinpath(@__DIR__,"src","assets")

Sys.rm(models_dst;recursive=true,force=true)
Sys.rm(assets_dst;recursive=true,force=true)

Sys.cp(models_src,models_dst)
Sys.cp(assets_src,assets_dst)

pages_dir = joinpath(@__DIR__,"src","pages")
notebooks_dir = joinpath(@__DIR__,"src","notebooks")

Sys.rm(pages_dir;recursive=true,force=true)
Sys.rm(notebooks_dir;recursive=true,force=true)

repo_src = joinpath(@__DIR__,"..","src")

# Add index.md file as introduction to navigation menu
pages = ["Introduction"=> "index.md"]

binder_logo = "https://mybinder.org/badge_logo.svg"
nbviwer_logo = "https://img.shields.io/badge/show-nbviewer-579ACA.svg"

for (i,(title,filename)) in enumerate(Tutorials.files)
  # Generate strings
  tutorial_prefix = string("t",@sprintf "%03d_" i)
  tutorial_title = string("# # Tutorial ", i, ": ", title)
  tutorial_file = string(tutorial_prefix,splitext(filename)[1])
  notebook_filename = string(tutorial_file, ".ipynb")
  binder_url = joinpath("@__BINDER_ROOT_URL__","notebooks", notebook_filename)
  nbviwer_url = joinpath("@__NBVIEWER_ROOT_URL__","notebooks", notebook_filename)
  binder_badge = string("# [![](",binder_logo,")](",binder_url,")")
  nbviwer_badge = string("# [![](",nbviwer_logo,")](",nbviwer_url,")")

  # Generate notebooks
  function preprocess_notebook(content)
    return string(tutorial_title, "\n\n", content)
  end
  Literate.notebook(joinpath(repo_src,filename), notebooks_dir; name=tutorial_file, preprocess=preprocess_notebook, documenter=false, execute=false)

  # Generate markdown
  function preprocess_docs(content)
    return string(tutorial_title, "\n", binder_badge, "\n", nbviwer_badge, "\n\n", content)
  end
  Literate.markdown(joinpath(repo_src,filename), pages_dir; name=tutorial_file, preprocess=preprocess_docs, codefence="```julia" => "```")

  # Generate navigation menu entries
  ordered_title = string(i, " ", title)
  path_to_markdown_file = joinpath("pages",string(tutorial_file,".md"))
  push!(pages, (ordered_title=>path_to_markdown_file))
end

makedocs(
    sitename = "Gridap tutorials",
    format = Documenter.HTML(),
    pages = pages
)

# Documenter can also automatically deploy documentation to gh-pages.
# See "Hosting Documentation" and deploydocs() in the Documenter manual
# for more information.

deploydocs(
    repo = "github.com/gridap/Tutorials.git"
)