From a30cd8a40c2078feb0f5edc5a98da19e3885c746 Mon Sep 17 00:00:00 2001
From: Oceane <oceane.fourquet@outlook.fr>
Date: Tue, 7 Feb 2023 16:47:48 +0100
Subject: [PATCH] Mise au propre

---
 .../cost_matrix_uncertainty.cpython-39.pyc    | Bin 4824 -> 4793 bytes
 .../dynamic_preselection.cpython-39.pyc       | Bin 10739 -> 8692 bytes
 ...onic_regression_uncertainty.cpython-39.pyc | Bin 12839 -> 12781 bytes
 .../optimal_k_aggregations.cpython-39.pyc     | Bin 4703 -> 4321 bytes
 .../__pycache__/show_results.cpython-39.pyc   | Bin 5682 -> 8815 bytes
 Module/__pycache__/stages.cpython-39.pyc      | Bin 2902 -> 2039 bytes
 Module/__pycache__/tools.cpython-39.pyc       | Bin 4356 -> 4371 bytes
 Module/cost_matrix_uncertainty.py             |   2 +-
 Module/dynamic_preselection.py                |  60 +---
 Module/monotonic_regression_uncertainty.py    |   9 +-
 Module/optimal_k_aggregations.py              |  28 +-
 Module/preselection.py                        |  59 ----
 ...show_results_4cases.py => show_results.py} | 271 +++++-------------
 Module/stages.py                              |  46 +--
 Module/tools.py                               |   7 +-
 README.md                                     |  40 +--
 run_mem.py                                    |  99 +++++++
 17 files changed, 222 insertions(+), 399 deletions(-)
 delete mode 100644 Module/preselection.py
 rename Module/{show_results_4cases.py => show_results.py} (58%)
 create mode 100644 run_mem.py

diff --git a/Module/__pycache__/cost_matrix_uncertainty.cpython-39.pyc b/Module/__pycache__/cost_matrix_uncertainty.cpython-39.pyc
index a39af419af09ac84330c78ad6a8a94e5580258a5..eaa56ea6a45882d764e09782f1633c6338042275 100644
GIT binary patch
delta 1020
zcmZ9K&rcIU6vw+iy3m&LLnX0_B1*v`w1N^f2BT6@L4#2sW=v?d+iBg{-C5sm2|W?G
z7_ZL7t9lVm8cs(40Z(4ZTuium@PF{VB@yE$`<XZM-n^OlzPFeElF!)LY&wBo-_!li
znWmPXD=mi{!jh<q7QAfnQdu}HkNZ(r^0-$C+R=02?|#+lS{E~GuH9fp1d~io7(b3N
z19(Fj)c^=prU$@euUXcLyUS)<OCQH`uHX+jxtE+Oo*?ri!5|C}P7zKM1_@^fLxi*P
zsx>%2OlF=iLKr2SClnAYDOyn_fHATyPt<rbWF2^=3I~933Y#F80hNHsch-V7wfo!J
z(KRODrgpTPROta(Nmp~{C^SpxCeXDVGAQD8nqE*pn0lFe9VIlkbtb=MCP&C6Vi!WC
zTE4>}vR(fdJ+Pp|HS$f%qh0>Sbuw=dZX(ck8wZ5~djFhE`L^(f966H@78hq%3I@#4
z(hOl1feVzE>D4w&(|jlvRp}yBR)a^}UsJjlF!PZRO=UVFXtT~@jq`v^Na7Zy2Q`)|
z+mSs7w#N^(SEkz(4qTSS?BL22MH-&H&a5XKTplVTj6j(_Zc&yae8-MhXCx|hN}{wS
zD8{+{KpDR6!zG$o_(HM9nQlj5;R2H%vU#k)_w1&2OD=R@$i(WC8gNH$c5i8`((KtU
zlgx$GVSgy|1#gG(?GLXTXFO=Bixl69ZGh*v>p)4F9P1s{Cgo!9W6hE8dq2*^LTVJL
zF#{ipW$4ElR1w=cJi`I6UaS9Cl1~(qldt+FN9j$lLipRSn1s_tR2t=p+o&dg_Kj~e
zaJA5{tcRl3YI4wNSKQmw9V+R!JS@i&*;ZitH9Ld_3b{)wX5^xzDL2A~!ZL<nl4~Bp
mdc0OMasv<!4@1{)z<qM{5J-QZvcYO1(U|~;%!Yh(WbO}d_Vuy=

delta 1051
zcmZ9LyKfUg5XN&4Ut$|O0YQN<gjWKA5EBHUAV5T{h(}%o2#CfypV!F=`}UYUM{xv-
z2sG5&LQhhGQXv{@3TV-kNEDPv`~mEDDT1)%-_7jI&h36P_i^C+K;ADDa$V+E`ttBY
zzG+oN`GFFo%CaHb^t3I?6&bW!B1%+wZpEk2kB(0IQ6Q+iAXK}VsOmfkC7L2gLK#)(
z{gBl58>?aMVYeRoOY9^x%DU)$+s_UO<JV#WYHS-r|8^?Y#qBY-W91H+V_Y_WD(R1z
z3nPbN9swMnA2<pe1C9eHfRn(0KIrw|J_YkMFa(?d&H}>*k2A8JRAV}4Z1!5RE}DwF
z&5^2th|VKz6d{MIG3yQQjy1mh)!VWy)}8E@RnnhwB|VX=9UMez0Vo1Eb^rqzuX8ty
z+1PPs^EbOM8FSNS{Wd>3h>%P}2Apj}#>5Y!U%23qO%=o@^q+jRJ_Yj@FufC-H4g~b
z`sdB4w}G4zf|=>Lxyi*LhZeAO6PPnF3#iL>twR&=kENorEfsr9A`#IF+pU=0c`2Lh
z1~Tq&&q!T}7$#-Xy>Xqh6+iK($Zv^V?b!{RGN9|ax6r>hj!dWJud;VfP$(2TDj{|w
zvxU7tMuDGjPa>-g6k+Q=T}*37F*}hT(KUFUxuIMUZ2Jj$SkSKu1EvF8g%{S09xk5E
zr|Lrux~pr&4NK{t#UB;OJe1v?4|bo3j!I9zd)&0*&Pa_RzsHP$c~7`XD9SqDchb6|
z&-X1@Yx-s1yQ`^?7BVe%%tcL$4j7L*2Aej;*yKd@#(yn&kDQWT-aC2<ccNwBIDmOI
zMV^}nls59DWAsda-aEX$j^F|IW@NqH6l7yVI@_2I&P45&X-5OL7yD7&SM(Su_p#z8
zp^-EjCT5^a8x^?-Jwm9rWxmodCK(8&!f1&W5$Xk?KcQ`;y1IJ0XbtANR{N&@0)#OT
A@&Et;

diff --git a/Module/__pycache__/dynamic_preselection.cpython-39.pyc b/Module/__pycache__/dynamic_preselection.cpython-39.pyc
index 6e7a5d749d3ae53b8cb678e579961c50add26f61..114f2d5e86efdad995af1333c3fbf2261be7052f 100644
GIT binary patch
delta 3214
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

literal 10739
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
AKmY&$

diff --git a/Module/__pycache__/monotonic_regression_uncertainty.cpython-39.pyc b/Module/__pycache__/monotonic_regression_uncertainty.cpython-39.pyc
index 261caf75a92252ad4805cf09d5d7d5d480095b10..df45ec257726d79ba4d83283b4c71ef2b3ac62b7 100644
GIT binary patch
delta 2735
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
NdP@_t^E)k@{sT4)AV~lK

delta 2873
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

diff --git a/Module/__pycache__/optimal_k_aggregations.cpython-39.pyc b/Module/__pycache__/optimal_k_aggregations.cpython-39.pyc
index 278c9521ba1737d10a989dc280157324a77ae69f..0795f9292d3c7fd7fb975537ea5cd593c57a13a3 100644
GIT binary patch
delta 884
zcmZuv&1(}u6rVS{+1>0{cGIs!3u@a#Ba~V{q30C5C_;-^X{a%iwrSHOootoDEGeYY
z^dJQ0;?3mZUHnTtcyKR%AU*g8=+!q`kfO89Z{K_Sd+#^z&3>Bsa>Xxuo=tFlu6(Wh
z4Bq-7g(Z2JUa)toyX&okXsg+HSD{lz$5gDdHIDBzZVh+44}>sa^oT@6q=dn=3DTuS
z(uEU<NCX0{E)+>0N_S&3q60c4u_eg1CQL>cc|kX5p2TTE2D&geVF<A;?CliO@kza;
zKq6ycc7!cJP@xU=*uj7$oFSZ`Ak%gz{}H8oWMB`KC_N^}SdtmcJhCwA42e2S><X7z
zd9n$y7r9t1Ej(4Pn_8o>A7?~{rFS%b+5@KL$-s+zk!E(D2tS9}!wvvxSW$*KU9^<!
z9TKO`cU;<vgR}m^C_o9PM?`=kde>Of;%qz;kDf`7{43oD{<H@o_>VX$-uNrthdq67
z<`_1Bxj1&~{2{Q@F)_AG3f_JB-F`K}4ZNh40!?(ro2|sGHCpv@r79OQMd`S+@K`=@
z3bN$hmhauI={+QKAE6NPd1YTiNc5<-TTS#@y;<Q8Wyf3blT?e>8WEpT)Nz@3vj%J@
zG+K~>ziO<h%tx~6PcPm?lW4hA7A%?t7knCMwq{Wma$swtV8JA{sHNd|jEqtneV<NJ
z-j=8SAkS4LM}hkPxU0ZJIFPS1SC=Zvom0RN3Y7n*EBg;UQkKd|(#;n3P_D1<JV&>!
zW<u~ZIpF)!4?X~s--04=SqSGLmaE~#u|s4O@`-V;$@c42PSNF0<ViRQCHW@2j&u7M
iUYdEP!fFV-s9;$^Tfx49Lj|T>a7N^Oc22ux8NUEPSj1HT

delta 1285
zcmah{&2Jk;6rVTiwb%P)$8lP_MC!IwD6S}hUXYOBKpjp{BGLmNDbZ?Yoo@WG?(77R
zGusGU6z5PWXt;2*ufPRy<=;R;3lieUg};F}#E23hvDW-%-t&9E-<vn@w`;%N@I%kD
z34VX{ZbUydzVlZoFcr`%owq*<c@mC-JK-pb`Q|%ub~q5(-Zqc3co0V-Nk@CzVZyWT
zyYzbb*wQ4+uZ4RRmw_w0NeK~z!5pNqfGGfBlo^kSpsXazQ`#j{I0Zq4A@MYYE;)ny
zzvPxE%}WcCSA{7n%$(BPmiD~N%E)6aV1YbnR~7_!a$p@xixEaXr#;#xxg*KEDy@AC
z%U$Un*sOv->j?!SoH=?VNQ&i@a_<6t^=V>^^`y6eQzA`f_vsn%*M&bL^V&ieO;5-P
z>M@78kB=>M*B3<JCikV!yf)c~ye3vq%#k%MH#K)@Ue8zL3iJC0lHHyGv)g3e5UbK*
zwKkFU7Ut^`Mi%z0uDhkBUnaRJs5H;}b^pt}vFy&OXd=HiBge9V5~XQ**T|dsT7GFM
zy!M~MU(Y}`{!jQqXI8NBOIf+vA`AL-r_PSy;hPr{8gn?WQdTkiUoZCXg%jujTg5rB
z{<#-+?y|hRLpsg7lXgECCRsEHvn=T)QK-i)cqKT>?Fg1rrZ=1|Qo^;Pp0_{S`dtrP
z0pY~m#)NnzFg~#Fb!bsyJRKL6WHcUxQ9QX6rI`qZq2S3UL6i>1hazTy&C8gte(<`g
z>TE!$q}@@wW>qog)@zgJ?(q1$jA1OoVann`&`WvH4_?(W$p|qE>`8NL#Deis|8KAQ
z!g=t<r^wEIgw9%Fj(IW?MHv}%8JqgA7ZHk*NQQAyO2_f2FhAyrhzm0sq#62>K^pOQ
z)w+AH!mn$ZmU`rF_{JdJFW{h{;-vz5>Rb1{@`sx4edT!1-n)xO0zPe;4Y0t5I${G{
z^wbR-ZOgC?o4U{f+i0S_PAzH~K1Q{mNzZK?u7HbY9n+%xNImf8?TOZKG*mRW8a#wk
zb<MxIb)d~#8u|zw%Kr-2=ksu>PdcZlrenNvIN0l-pqc3>AXr}uc&^U;AEB>$wJuE5
zH?>W8qJFMDvo^zsPP-_-m9oP@%=HZLedW~G@yRyow_#U(P``Thk#_4g@vep)4M!Ss
O4KwvseaqOg%6|fLgf(LT

diff --git a/Module/__pycache__/show_results.cpython-39.pyc b/Module/__pycache__/show_results.cpython-39.pyc
index 2a77523ab471eb02977f182b7253a9182f0e5c99..2dd8754d800151e48f662369dc523fc144bf777a 100644
GIT binary patch
literal 8815
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
B!5aVo

literal 5682
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
M`epx8a5Z@IUyEo6<^TWy

diff --git a/Module/__pycache__/stages.cpython-39.pyc b/Module/__pycache__/stages.cpython-39.pyc
index 8619cd1ba1731d59207ef468dfe6812fdfd0bbfc..b8af48a39981829c186d7e93d4c7b8b26babe952 100644
GIT binary patch
literal 2039
zcmZ`)OOG5i5N`K-o;#0yWRnO5$bsRtun`v&AtZ7o5(->eK`n2$XVRH|#r8y5$$eUo
zxbPo##3@&Pj*oESFL2_sXR{;`^r-F6E>}%ex$0{=8ucAKzg2%^>&S8bG>g|C7mKg)
zieE6~PEJavB8f{3c7eUbx7Y&?lF(uwI7%Xm1K>F6SsViQlYzxiIZQ^d5tZX=FPU8J
zO_OOJ=e?htWR~~y0p@u=%tx5_^Krh1`5=!TIg80(@WxpXeUvpqrWKXEc#&@EjB!be
zTAo96*tD{!Xqm24x>|9zqOxde0m+@JsT<kUMV4ZlGa(>&OFNKFQ<}qb!Ah1H)s&X2
zh8OZlh3)<PyrvZ_w9tQb;$h|)zpkDTvw6S4E8fE(olByeE$KWUS9!`&t|D9ivD^7w
zpn^xvOY(5xX+Lj8napTerdd-ji`9njd`||~E~KZ6P`mk3hxJ+3ZiFUP67EiG@|_M^
zT5$2w;d}VszrQ&7K`<^(nq{-$&o=DjL6dDNR!ebGu_|rP<&&m9`L@Y7B|8z4u9*0=
zJ=dXypBWRv1mciB*(ZDol%ZCxA5%d+yf)B}0d|2ZqI?yq06}`&sEcgS(Uu_Gxa+A{
zMN9XQ!(%8QXs=n*WPhDjg%DXuaVN_nvtcK_>ziEkx%o5gWu-`hs;JX7Ci)^>^MTn9
zghZ-zutX_H9j#NwdBb(EPGKSmu);|b&u*9)oybO+etv|-RhWllO!y6~-w5*-Hm<|G
zOH7y-Z@f$YvEM}|xUMgWbd_^KF31Dt$KShwa-Mo>fP!~^c9-t4(+!n#>8rttpdLnQ
z^fbr`e(tYmEg4=$YGl(FZ2fMGb*#oXw<mj-eMrV?4@pIGx8Y;2n{?A|2FU=Dp_*bp
z*ak@QyxUjN<xpZb_l_MkzX5-?ggB~yIaK==#XweSS3Rue20i-#n&aHxnkb?Ra?9xs
z<lf~(^>J<9*6R+jnyNz;Z{6+)c!vG{)`d4Wy5sJqI)LnG>7iAFhu<$;lr(Qz9Tjz3
z(v0a)Qodr6BZ<ypuKltQxHV4e71LhH>clU~CgaBt>w#%7nHF`<Uf|-ZjUL)tz3O^B
zu@vyCWKiaOX4EE2XrT8iCTZ2=tW0iaoKeYAihXo#USwd7S5h6)wq<p$J$fc|kTsiH
z@&JaC9^GWA$QsU)xoxnVfoI^4Wc)cTlR0Ybs$LlkHxP)$EnBC24g=g2RuUU4%c5kq
zQ2Buo>|@ZO4Mrs4c`Esanb|m(L}qTzs3rw^V<QtkU#6!zsxd)D`zCDdRnHk88#}(C
zhQznJ!A{eoS%!EvnRc^6hb28@Xq(UqMKZdk%e0l^f4buI9oQCkF*xM5J0UYNBxB5d
z?<P5P4?zfHGW2F<bZ3O0;#_8_!f4<zU1=KJQp0_KYijV6kJ=6`DTJu)NP6f82ZRwB
z!axn1+P1x<dMf;vDgu57cKEwyFsy2?o4*gV7`&DBw{p!tG{-+OgJCI~H~xu1|4j+^
zzJyE|_Z@<e$xXuV0WS`9xZ_H0zK%P0JcCT(aUTQjg>P*6aFY$~3d#**a>E}wY*B(#
zXt&LiDZX88*~qdu1LYco3);<ITT1OV!V<2fBb#6A!)qQ}-z}5H_fhDe@UKi;3BzAQ
RT-Vjlje+7Ij^il4{SW?l2~Ge2

literal 2902
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
P&m(X~PS6Mfe4qRmyH^3x

diff --git a/Module/__pycache__/tools.cpython-39.pyc b/Module/__pycache__/tools.cpython-39.pyc
index 3335ebb09460a99f00dcbc32116d144a20c70a59..cff49bba8b77852765176cdb3db435a582510586 100644
GIT binary patch
delta 861
zcmY+C%TE(Q7{EK*-9EP6zJLNf2ow-kgpDaG!U0W@Xh<N@;9)Lxx-)&qzL?z_+SGV4
z98mNyM-x*{#-rgM(34)gdD?g|{so>rIfG4%GnwCf`+f7hX7+iRl{KVkYJ`tpt)J%i
z51J0<SByQMP~UJHZigOph_UIK9h*3TZ`j1HdEKDpI%hrbJ_;b4QyO4~y-<!g3$Y5<
zY{ej$XQ#1Gpv=tp%c(^k+>DA8!;$5Cg0CuH{xQoWe(WCwsmJMlq94ZzoW$yh3?f2<
z6)ZQUAyYVwwZE2uh5^nrrBfiz4Kn|IWpQ?>&*9uq%H#YX85H_yTwt~2<l+b(J>kB6
z36G6Oo@RKi(SBwyhKqRoRKgQ@@<ig+^n-|AVy}}At5C&=?z<E@P0~x=->puY9r}dm
zQmB}&<x;3vs7@>>H!14&q@^WYqE~o(Fln_N;s;%euv_Y*-Cn{#9dp^kjh<u}zkvaj
zpxtZ*I)JHq-94<e9kWGzy%<W42V>|wAr&`BF9?(c#yG;L-?1V4q8b{MJ<AQCd}y_~
zMoz61!#E|Lg-oJn>74MG6&~zPsthi&R%%@hrRu#<c92cjyVMj|WuH?E#R4dS44*2W
zWsn95Py}@2OiJg$w7~;F**~BGUFD*l45Pe{^SDsjxe8fDTUILEa?BdqEU573A3b}k
z86YkmnRmy&WxQwqs+T+*CO1)lwkR(GDv0uXqbnjytkG_EC<!Is;Z2eN##;mhHuC5-
zZl>1-ZV22ISmV%D80*$3K~~6jj}i<u({&m(8wIsS+ah#99K9rdbE*qmW?!>w;0;UU
z)(hJr0@%?<LdEIWUY8ndFE>>ZwS=<ia)rc2821UPyVRj~*{j?{X-0&Z7dU^M4IzpC
O={EbAyB(cN<o^Jj=-hMw

delta 915
zcmY+D&2Q5%6u|4WX_vO?+I_H(15EAE7GNugiNkh)t=%L(#HMY4lpTr}yCow{vX^A6
zQ^h1eNJ#AD6G%wgkt5oT8y7Ahap7cfK;jSJz(0W9RzleF&-Q!I@A<trtoWj+V_i?j
zMEm;Xf%Wl&ZlLN$`CdRFD0_7;g58LgtDY4#sT&66)jbS0b|)&>wJ4O=X%IPKP+J2U
zP={Kf?YXrzY(sFmh2F;zXR2C9Mdqk41^=j5g=8veqAB()`3aR+HTC-3jEHT;<qdi*
zCuU8IiWotg{Z9Qn+z&H5*>+z$Mf!+F(j-H&L_bQQn3NNhBpOPOIbqR%l#rTZogk8L
zC?}}1%l)_OCxxCoPX>Cc0vSBk!hv>{3_VxcI#I`Bf{C$M@g&|g*%>6m<jhgm;ZVEd
zx}DvK86)hec7N+YnVI2fg5j|T*lkeg6Db^M>#LOsD}p_`VyIkmY?lUM%b{GgJjVl5
zah`D1!Q0d^Q<h`<HP7V<7w@$U1uhE*P!?b#>4($CFjrikCvn%itQ?$`C`k+p@OTh4
zIs2S0>pbB*UdR*sjx8igW==P9a9$ct3YhFpriiAQmsyxJmC8-XNKFT_{#?V6RSPT+
zXkBcBYwUYwYG@RVqnzkz(TgZ62+OC1YynNo$uo&y7eZJPOG7i`!a+BZa`y^nOZu!j
zFEp=Mq?geA=^MR*Qn#e3coM&I{^7qA6rXUdibK2txGAcH0dNZzWQ1hhZbU%261XB$
z8k(s`6o*ah!*!vC8xo5W^6fxXz(||PRt+e2<m>|_rfzv|z1GBGt!_IM3~72n{sM4O
z;u8DOKabwBk^I8#P3ZyMH3qrrMoqs3ojeQTtgNkLZ_oOzPL-40xqHim<q1<ooHbJc
j#oHdZu+HA)N5_jYz?4Mi+bzqLtO{(hZ~4V|sju)CnuPN7

diff --git a/Module/cost_matrix_uncertainty.py b/Module/cost_matrix_uncertainty.py
index a04024b..ae05749 100755
--- a/Module/cost_matrix_uncertainty.py
+++ b/Module/cost_matrix_uncertainty.py
@@ -10,7 +10,7 @@ from itertools import chain
 import copy
 
 
-import multiprocess as mp
+import multiprocessing as mp
 
 
 ### Useful functions for parallele
diff --git a/Module/dynamic_preselection.py b/Module/dynamic_preselection.py
index 6c71fd6..9fdeeca 100644
--- a/Module/dynamic_preselection.py
+++ b/Module/dynamic_preselection.py
@@ -28,9 +28,7 @@ def H_df(df, cls, nbcpus):
     pool = mp.Pool(nbcpus)
     vals = [(c, df) for c in cls]
     res = pool.starmap(monotonic_model_RE, vals, max(1,len(vals)//nbcpus))
-    #f = open('logs_H_df.txt', 'a')
-    #f.write('H d_f {} \n'.format(res))
-    #f.close()
+
     return sorted(res)
 
 
@@ -108,11 +106,11 @@ def deleteNode(array, num):
         if num == array[i][0]:
             break
 
-    #print('array 1', array)
+
     array[i], array[size - 1] = array[size - 1], array[i]
-    #print('array 2', array)
+
     array.remove(array[size - 1])
-    #print('array 3', array)
+
 
     for i in range((len(array) // 2) - 1, -1, -1):
         heapify(array, len(array), i)
@@ -263,19 +261,15 @@ def check_disjoint_pairs(Q, param):
                 if len(dis_p) >= param:
                     flag = True
                     break
-    print('Pairs with {} genes'.format(len(genes)))
     return flag
 
 ### Preselection based on the number of genes
-def algorithm_1(cls, df, k, nbcpus, logs):
+def algorithm_1(cls, df, k, nbcpus):
 
     t0 = time.time()
     H = H_df(df, cls, nbcpus)
     t1 = time.time()
 
-    f = open(logs, 'a')
-    f.write('H computed in {} en len(H) = {}\n\n'.format(t1 - t0, len(H)))
-    f.close()
 
 
     Hd = H_dict(H)
@@ -305,10 +299,6 @@ def algorithm_1(cls, df, k, nbcpus, logs):
             break
 
 
-    f = open(logs, 'a')
-    f.write('Old G {}\n\n'.format(G.keys()))
-    f.close()
-
     a = max(Q.keys())
     G_ = deepcopy(G)
     del G_[a]
@@ -319,9 +309,6 @@ def algorithm_1(cls, df, k, nbcpus, logs):
         G_ = deepcopy(G)
         del G_[a]
 
-    f = open(logs, 'a')
-    f.write('New G {}\n\n'.format(G.keys()))
-    f.close()
 
 
 
@@ -330,22 +317,9 @@ def algorithm_1(cls, df, k, nbcpus, logs):
     Hd = supp_H_below_a(Hd, h_key)
 
 
-    t3 = time.time()
-    f = open(logs, 'a')
-    f.write('S1 computed in {} and size pairs={}\n\n'.format(t3 - t2, Hd.keys()))
-    f.close()
-    f = open(logs, 'a')
-    f.write('G {}\n\n'.format(G.keys()))
-    f.close()
-
-
-    t4 = time.time()
 
 
     for h_key in sorted(Hd.keys()):
-        f = open(logs, 'a')
-        f.write('H_key {}\n\n'.format(h_key))
-        f.close()
         a = max(Q.keys())
         if h_key <= a:
 
@@ -364,9 +338,6 @@ def algorithm_1(cls, df, k, nbcpus, logs):
             G = update_dict(G, Gd)
             Q = update_dict(Q, Qd)
 
-            f = open(logs, 'a')
-            f.write('Old G {}\n\n'.format(G.keys()))
-            f.close()
 
             G_ = deepcopy(G)
             del G_[a]
@@ -377,19 +348,11 @@ def algorithm_1(cls, df, k, nbcpus, logs):
                 G_ = deepcopy(G)
                 del G_[a]
 
-            f = open(logs, 'a')
-            f.write('New G {}\n\n'.format(G.keys()))
-            f.close()
     pairs = list()
     for key in Q.keys():
         pairs += Q[key]
 
 
-    t5 = time.time()
-    f = open(logs, 'a')
-    f.write('S2 computed in {} and size pairs={}\n\n'.format(t5 - t4, len(pairs)))
-    f.close()
-
     return Q, pairs
 
 
@@ -397,15 +360,12 @@ def algorithm_1(cls, df, k, nbcpus, logs):
 
 ## Preselection based on the number of pairs
 
-def algorithm_2(cls, df, m, nbcpus, logs):
+def algorithm_2(cls, df, m, nbcpus):
 
     t0 = time.process_time()
     H = H_df(df, cls, nbcpus)
     t1 = time.process_time()
 
-    f = open(logs, 'a')
-    f.write('H computed in {} en len(H) = {}\n\n'.format(t1 - t0, len(H)))
-    f.close()
 
 
     Hd = H_dict(H)
@@ -438,9 +398,7 @@ def algorithm_2(cls, df, m, nbcpus, logs):
 
 
     t3 = time.process_time()
-    f = open(logs, 'a')
-    f.write('S1 computed in {}, H size pairs={}, Q size pairs = {}\n\n'.format(t3 - t2, Hd.keys(), Q.keys()))
-    f.close()
+
 
     t4 = time.process_time()
 
@@ -472,9 +430,7 @@ def algorithm_2(cls, df, m, nbcpus, logs):
         pairs += Q[key]
 
     t5 = time.process_time()
-    f = open(logs, 'a')
-    f.write('S2 computed in {} and size pairs={}\n\n'.format(t5 - t4, len(pairs)))
-    f.close()
+
 
     return Q, pairs
 
diff --git a/Module/monotonic_regression_uncertainty.py b/Module/monotonic_regression_uncertainty.py
index 48cb10f..88b43b6 100755
--- a/Module/monotonic_regression_uncertainty.py
+++ b/Module/monotonic_regression_uncertainty.py
@@ -56,7 +56,6 @@ def Z_(H, A, ind_leaves):
     for i in range(1,len(H)+1):
         v_i = ind_leaves[i]
         Z.append(int(compute_Z(A,v_i)))
-    print('Z', Z)
     return Z
 
 def is_A_balanced(A):
@@ -176,7 +175,7 @@ def step1(ind_cg, A, nb_leaves, ind_leaves, err1, S, H):
     else:
         A[ind_leaves[ind_cg]-1] = mini + err1
         degenerate_interval(A, ind_leaves[ind_cg], ind_leaves)
-    #print('Step1', time.process_time() - t0)
+
 
 
 
@@ -241,7 +240,7 @@ def step2(A, v, err0, err1):
     #add the error in left and right intervals
     update_all_right(v, A, err0)
     update_all_left(v, A, err1)
-    #print('Step2', time.process_time() - t0)
+
 
 
 
@@ -615,13 +614,13 @@ def compute_recursion(data, case = None):
                     models[4] = (reg_err, bpr, bpb, r_p, b_p)
 
     else:
-        #print('case {}'.format(case))
+
         rev, up = case[0], case[1]
         X, H, A, ind_leaves = initialization(data, rev)
         S = list()
         labs = [x[2] for x in X]
         nb_leaves = len(H)
-        #print(X)
+
         for i in range(len(X)): #((r,c), w, label)
             x = X[i]
             xy, w, lab = x
diff --git a/Module/optimal_k_aggregations.py b/Module/optimal_k_aggregations.py
index a0ca582..20b7218 100755
--- a/Module/optimal_k_aggregations.py
+++ b/Module/optimal_k_aggregations.py
@@ -63,19 +63,17 @@ def create_and_predict_metamodel(df_, out, pairs, nbcpus, funct):
 ##Big loop to compute the average error for ensemble contaning k classifiers
 
 
-def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log):
-    print('k misclassification : {}\n'.format(funct))
+def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k):
 
-    k_mis = {k : list() for k in range(min_k, max_k)} #Store for each value of k, whereas patients were misclassified or not with an ensemble of k classifiers
+
+    k_mis = {k : list() for k in range(min_k, max_k+1)} #Store for each value of k, whereas patients were misclassified or not with an ensemble of k classifiers
 
     #pairs_err = {cl : list() for cl in cls} #For each classifiers we are going to store the average misclassification error (computed with LOOCV) made with each patients
 
 
     for j in range(len(df)):
         t1 = time.time()
-        f = open(log, 'a')
-        f.write('Patient {} \n'.format(j))
-        f.close()
+
         out = df.iloc[j, :]
         df_2 = df.drop([j])
         df_2.reset_index(drop=True, inplace=True)
@@ -83,11 +81,6 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log):
         ndf_err = cmu.error_matrix(df_2, cls, nbcpus,funct)
 
 
-        f = open(log, 'a')
-        f.write('cost matrix computed \n')
-        f.close()
-
-
         cost = cmu.cost_classifiers(ndf_err)
 
 
@@ -107,7 +100,7 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log):
             min_k +=1
 
         #k > 1: ensemble classifiers
-        for k in range(min_k, max_k):
+        for k in range(min_k, max_k+1):
             t0 = time.time()
             mve, pairs, algo = find_k_metamodel(df_2, ndf_err, cost, k, nbcpus, strat)
             pred, proba = create_and_predict_metamodel(df_2, out, pairs, nbcpus, funct)
@@ -117,16 +110,7 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log):
             else:  #case of proba = -1 means that all the classifiers in the metamodel predicted the point as uncertain
                 print('case of unknown point in oka')
 
-            f = open(log, 'a')
-            f.write('Creation metamodel for k = {} in {}s \n'.format(k, time.time()-t0))
-            f.close()
-
-        f = open(log, 'a')
-        f.write('End patient in {}s \n'.format(time.time() - t1))
-        f.close()
-
-
-    k_error = {k : np.mean(k_mis[k]) for k in range(min_k, max_k)}
+    k_error = {k : np.mean(k_mis[k]) for k in range(min_k, max_k+1)}
 
     return k_error
 
diff --git a/Module/preselection.py b/Module/preselection.py
deleted file mode 100644
index caffa4d..0000000
--- a/Module/preselection.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from Module import cost_matrix_uncertainty as cmu
-from Module import optimal_k_aggregations as oka
-from Module import monotonic_regression_uncertainty as mru
-from Module import tools
-from Module import selection_algorithm as sa
-
-import multiprocessing as mp
-
-import pandas as pd
-import matplotlib.pyplot as plt
-import os
-
-
-def all_configurations(df):
-    transcripts = list(df.columns)
-    transcripts.remove('target')
-
-    configurations = list()
-    for i in range(len(transcripts)):
-        for j in range(i+1, len(transcripts)):
-            for key in range(1,5):
-                configurations.append('/'.join([transcripts[i], transcripts[j], str(key)]))
-    return configurations
-
-
-def single_score(cl, df):
-    p1, p2, key = cl.split('/')
-    key = int(key)
-    rev, up = tools.equiv_key_case(key)
-
-    diag = df['target'].to_list()
-    tr1, tr2 = df[p1].to_list(), df[p2].to_list()
-    data = [((tr1[i], tr2[i]), 1, diag[i]) for i in range(len(diag))]
-
-
-    X, m = mru.compute_recursion(data, (rev, up, key))
-    reg_err, bpr, bpb, r_p, b_p = m[key]
-
-    return (cl, reg_err)
-
-def regression_error_score(df, cls, nbcpus):
-    pool = mp.Pool(nbcpus)
-
-    vals = [(cl, df) for cl in cls]
-    res = pool.starmap(single_score, vals, max(1, len(vals)//nbcpus))
-
-    dico = {r[0] : r[1] for r in res}
-    s = pd.Series(dico)
-    s.name = 'regression error'
-    return s
-
-def regression_error_matrix(df, nbcpus):
-    config = all_configurations(df)
-    reg = regression_error_score(df, config, nbcpus)
-    return reg
-
-
-def preselection_reg_err(reg_err_mat, threshold):
-    return reg_err_mat[reg_err_mat<threshold]
diff --git a/Module/show_results_4cases.py b/Module/show_results.py
similarity index 58%
rename from Module/show_results_4cases.py
rename to Module/show_results.py
index 25d9795..335ba85 100755
--- a/Module/show_results_4cases.py
+++ b/Module/show_results.py
@@ -131,10 +131,9 @@ def print_model(data, models, p1, p2, df1, pathname = None, cm=None):
 
 
 
-def print_model_log(data, models, p1, p2, df1, pathname = None):
-    #print the monotonic space with the 3 areas
 
-    data = [((log(d[0][0]), log([0][1])), d[1], d[2]) for d in data]
+def print_model_out(data, out, models, p1, p2, df1, pathname = None):
+    #print the monotonic space with the 3 areas
 
     if '.1.1' in p1:
         p1 = p1[:-2]
@@ -152,8 +151,8 @@ def print_model_log(data, models, p1, p2, df1, pathname = None):
 
     for key in models.keys():
         key = int(key)
-        #print('Key', key)
-        plt.figure(figsize=(3,3))
+        print('Key', key)
+        plt.figure(figsize=(5,5))
         ax = plt.axes()
         ax.set_facecolor("lightgray")
 
@@ -199,8 +198,8 @@ def print_model_log(data, models, p1, p2, df1, pathname = None):
                 ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1))
 
 
-        #plt.scatter(x_r, y_r, c = 'blue', marker='.', zorder = 2)
-        #plt.scatter(x_b, y_b, c = 'red', marker='.', zorder = 2)
+        #plt.scatter(x_r, y_r, c = 'blue', zorder = 2)
+        #plt.scatter(x_b, y_b, c = 'red', zorder = 2)
 
         random.shuffle(data)
 
@@ -209,6 +208,7 @@ def print_model_log(data, models, p1, p2, df1, pathname = None):
                 plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2)
             elif d[2] == 1:
                 plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2)
+        plt.scatter(out[0], out[1], c = 'g', zorder = 2)
         plt.xlabel(g1)
         plt.ylabel(g2)
 
@@ -224,29 +224,18 @@ def print_model_log(data, models, p1, p2, df1, pathname = None):
 
 
 
-def print_model_out(data, out, models, p1, p2, df1, pathname = None):
-    #print the monotonic space with the 3 areas
 
-    if '.1.1' in p1:
-        p1 = p1[:-2]
-    if '.1.1' in p2:
-        p2 = p2[:-2]
 
-    try:
-        g1 = df1[df1['Probeset_ID'] == p1]['Gene.Symbol'].values.tolist()[0]
-    except:
-        g1 = p1
-    try:
-        g2 = df1[df1['Probeset_ID'] == p2]['Gene.Symbol'].values.tolist()[0]
-    except:
-        g2 = p2
+
+def print_model_positive(data, models, p1, p2, pathname, cm):
+
 
     for key in models.keys():
         key = int(key)
-        print('Key', key)
-        plt.figure(figsize=(5,5))
+        #print('Key', key)
+        plt.figure(figsize=(3,3))
         ax = plt.axes()
-        ax.set_facecolor("lightgray")
+        ax.set_facecolor("lightcoral")
 
         x_r = list()
         y_r = list()
@@ -264,169 +253,57 @@ def print_model_out(data, out, models, p1, p2, df1, pathname = None):
 
         reg_err, bpr, bpb, r_p, b_p = models[key]
 
-        for bp in bpb:
-            x, y = bp
-            if key == 1:
-                ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightskyblue', zorder = 1))
-            elif key == 2:
-                ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightskyblue', zorder = 1))
-            elif key == 3:
-                ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor = 'lightskyblue', zorder = 1))
-            else:
-                ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightskyblue', zorder = 1))
 
+        min_x = min(min(x_r), min(x_b))-0.05
+        min_y = min(min(y_r), min(y_b))-0.05
+        max_x = max(max(x_r), max(x_b))+0.05
+        max_y = max(max(y_r), max(y_b))+0.05
 
-        for bp in bpr:
+        for bp in bpb:
             x, y = bp
-
-
             if key == 1:
-                ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor ='lightcoral', zorder = 1))
+                ax.add_artist(patches.Rectangle((min_x, min_y), abs(x-min_x), abs(y-min_y), facecolor = 'lightsteelblue', zorder = 1))
             elif key == 2:
-                ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightcoral', zorder = 1))
+                ax.add_artist(patches.Rectangle((x, min_y), max_x+abs(x), abs(y-min_y), facecolor = 'lightsteelblue', zorder = 1))
             elif key == 3:
-                ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightcoral', zorder = 1))
+                ax.add_artist(patches.Rectangle((x, y), max_x+abs(x), max_y+abs(y), facecolor = 'lightsteelblue', zorder = 1))
             else:
-                ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1))
+                ax.add_artist(patches.Rectangle((min_x, y ), abs(x-min_x), max_y+abs(y), facecolor = 'lightsteelblue', zorder = 1))
+
 
 
-        #plt.scatter(x_r, y_r, c = 'blue', zorder = 2)
-        #plt.scatter(x_b, y_b, c = 'red', zorder = 2)
 
         random.shuffle(data)
 
         for d in data:
             if d[2] == 0:
-                plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2)
+                plt.scatter(d[0][0], d[0][1], c = 'royalblue', marker='.', zorder = 2)
             elif d[2] == 1:
-                plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2)
-        plt.scatter(out[0], out[1], c = 'g', zorder = 2)
-        plt.xlabel(g1)
-        plt.ylabel(g2)
-
-        if pathname is not None:
-            plt.savefig(pathname + g1 + '_' + g2  + '.png')
-
-            f = open(pathname + 'gene.txt', 'a')
-            f.write('{} : {}\n'.format(g1, p1))
-            f.write('{} : {}\n'.format(g2, p2))
-            f.close()
-        else:
-            plt.show()
-
-
-
-def rank_h(x, D, rev):
-    h = [d[0] for d in D]
-    h = sorted(h, reverse=rev)
-    r = h.index(x)
-
-    if rev:
-        return len(D) - r + 1
-    else:
-        return r+1
-
-def rank_v(x, D, up):
-    h = [d[1] for d in D]
-    h.sort()
-    r = h.index(x)
-    #if up:
-    return r+1
-    #else:
-    #    return len(D) - r + 1
-
-
-
-
-
-
-
-def print_model_RS(data, models, p1, p2, df1, pathname = None, cm=None):
-    D_hat = [x[0] for x in data]
-
-
-    plt.figure(figsize=(3,3))
-    ax = plt.axes()
-    ax.set_facecolor("lightgray")
-    plt.xlabel(p1)
-    plt.ylabel(p2)
-
-    for key in models.keys():
-        key = int(key)
-
-        rev, up = tools.equiv_key_case(key)
-
-        reg, bpr, bpb, rps, bps = models[key]
-
-
-
-        for bp in bpb:
-            x, y = bp
-            rxd = rank_h(x, D_hat, rev)
-            ryd = rank_v(y, D_hat, up)
-
-            if key == 1:
-                ax.add_artist(patches.Rectangle((0.0, 0.0), rxd, ryd, facecolor = 'lightskyblue', zorder = 1))
-            elif key == 2:
-                ax.add_artist(patches.Rectangle((rxd, 0), 1000, ryd, facecolor = 'lightskyblue', zorder = 1))
-            elif key == 3:
-                ax.add_artist(patches.Rectangle((rxd, ryd), 1000, 1000, facecolor = 'lightskyblue', zorder = 1))
-            else:
-                ax.add_artist(patches.Rectangle((0, ryd ), rxd, 1000, facecolor = 'lightskyblue', zorder = 1))
-
-
-        for bp in bpr:
-            x, y = bp
-            rxd = rank_h(x, D_hat, rev)
-            ryd = rank_v(y, D_hat, up)
-
-            if key == 1:
-                ax.add_artist(patches.Rectangle((rxd, ryd), 1000, 1000, facecolor ='lightcoral', zorder = 1))
-            elif key == 2:
-                ax.add_artist(patches.Rectangle((0, ryd ), rxd, 1000, facecolor = 'lightcoral', zorder = 1))
-            elif key == 3:
-                ax.add_artist(patches.Rectangle((0.0, 0.0), rxd, ryd, facecolor = 'lightcoral', zorder = 1))
-            else:
-                ax.add_artist(patches.Rectangle((rxd, 0), 1000, ryd, facecolor = 'lightcoral', zorder = 1))
+                plt.scatter(d[0][0], d[0][1], c = 'firebrick', marker='.', zorder = 2)
+        plt.xlabel(p1)
+        plt.ylabel(p2)
 
-        random.shuffle(data)
-        for d in data:
-            rxd = rank_h(d[0][0], D_hat, rev)
-            ryd = rank_v(d[0][1], D_hat, up)
-            if d[2] == 1:
-                plt.scatter(rxd, ryd, c='red', marker='.', zorder=2)
-            elif d[2] == 0:
-                plt.scatter(rxd, ryd, c='blue', marker='.', zorder=2)
         if cm is not None:
             pair = '/'.join([p1, p2, str(key)])
             error = cm.at['LOOCV', pair]
-            plt.title('Ranking Space \n LOOCV Error {}'.format(round(error,3)))
-
-        plt.show()
-
-def print_severe(data, models, p1, p2, df1, pathname = None):
-    #print the monotonic space with the 3 areas
+            plt.title('RE = {} & LOOCVE = {}'.format(round(reg_err/len(data),3),round(error,3)))
+        else:
+            plt.title('RE = {}'.format(round(reg_err/len(data),3)))
 
-    if '.1.1' in p1:
-        p1 = p1[:-2]
-    if '.1.1' in p2:
-        p2 = p2[:-2]
+        if pathname is not None:
+            name = pathname + '/' + str(p1) + '_' + str(p2)  + '.pdf'
+            plt.savefig(name.replace('//', '/'), bbox_inches='tight')
+        else:
+            plt.show()
 
-    try:
-        g1 = df1[df1['Probeset_ID'] == p1]['Gene.Symbol'].values.tolist()[0]
-    except:
-        g1 = p1
-    try:
-        g2 = df1[df1['Probeset_ID'] == p2]['Gene.Symbol'].values.tolist()[0]
-    except:
-        g2 = p2
+def print_model_negative(data, models, p1, p2, pathname, cm):
 
     for key in models.keys():
         key = int(key)
-        print('Key', key)
-        plt.figure(figsize=(5,5))
+        #print('Key', key)
+        plt.figure(figsize=(3,3))
         ax = plt.axes()
-        ax.set_facecolor("lightcoral")
+        ax.set_facecolor("lightsteelblue")
 
         x_r = list()
         y_r = list()
@@ -444,55 +321,63 @@ def print_severe(data, models, p1, p2, df1, pathname = None):
 
         reg_err, bpr, bpb, r_p, b_p = models[key]
 
-        for bp in bpb:
+
+        min_x = min(min(x_r), min(x_b))-0.1
+        min_y = min(min(y_r), min(y_b))-0.1
+        max_x = max(max(x_r), max(x_b))+0.1
+        max_y = max(max(y_r), max(y_b))+0.1
+
+
+        for bp in bpr:
             x, y = bp
+
+
             if key == 1:
-                ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightskyblue', zorder = 1))
+                ax.add_artist(patches.Rectangle((x, y), max_x+abs(x), max_y+abs(y), facecolor ='lightcoral', zorder = 1))
             elif key == 2:
-                ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightskyblue', zorder = 1))
+                ax.add_artist(patches.Rectangle((min_x, y ), abs(x-min_x), max_y+abs(y), facecolor = 'lightcoral', zorder = 1))
             elif key == 3:
-                ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor = 'lightskyblue', zorder = 1))
+                ax.add_artist(patches.Rectangle((min_x, min_y), abs(x-min_x), abs(y-min_y), facecolor = 'lightcoral', zorder = 1))
             else:
-                ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightskyblue', zorder = 1))
-
-
-        #for bp in bpr:
-        #    x, y = bp
-
-
-        #    if key == 1:
-        #        ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor ='lightcoral', zorder = 1))
-        #    elif key == 2:
-        #        ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightcoral', zorder = 1))
-        #    elif key == 3:
-        #        ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightcoral', zorder = 1))
-        #    else:
-        #        ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1))
+                ax.add_artist(patches.Rectangle((x, min_y), max_x+abs(x), abs(y-min_y), facecolor = 'lightcoral', zorder = 1))
 
 
         random.shuffle(data)
 
         for d in data:
             if d[2] == 0:
-                plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2)
+                plt.scatter(d[0][0], d[0][1], c = 'royalblue', marker='.', zorder = 2)
             elif d[2] == 1:
-                plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2)
-        plt.xlabel(g1)
-        plt.ylabel(g2)
+                plt.scatter(d[0][0], d[0][1], c = 'firebrick', marker='.', zorder = 2)
+        plt.xlabel(p1)
+        plt.ylabel(p2)
 
-        if pathname is not None:
-            plt.savefig(pathname + g1 + '_' + g2  + '.png')
+        if cm is not None:
+            pair = '/'.join([p1, p2, str(key)])
+            error = cm.at['LOOCV', pair]
+            plt.title('RE = {} & LOOCVE = {}'.format(round(reg_err/len(data),3),round(error,3)))
+        else:
+            plt.title('RE = {}'.format(round(reg_err/len(data),3)))
 
-            f = open(pathname + 'gene.txt', 'a')
-            f.write('{} : {}\n'.format(g1, p1))
-            f.write('{} : {}\n'.format(g2, p2))
-            f.close()
+        if pathname is not None:
+            name = pathname + '/' + str(p1) + '_' + str(p2)  + '.pdf'
+            plt.savefig(name.replace('//', '/'), bbox_inches='tight')
         else:
             plt.show()
 
 
+def show_results_pos(df, pairs, nbcpus, pathname, cm):
+    pool = mp.Pool(nbcpus)
+    vals = [(p, df) for p in pairs]
+
+    res = pool.starmap(cr_models, vals, max(1,len(vals)//nbcpus) )
+
+    for r in res:
+        p1, p2, models, data = r
+        print_model_positive(data, models, p1, p2, pathname, cm)
+
 
-def show_results(df, probs_df, pairs, nbcpus, pathname, cm):
+def show_results_neg(df, pairs, nbcpus, pathname, cm):
     pool = mp.Pool(nbcpus)
     vals = [(p, df) for p in pairs]
 
@@ -500,7 +385,7 @@ def show_results(df, probs_df, pairs, nbcpus, pathname, cm):
 
     for r in res:
         p1, p2, models, data = r
-        print_model(data, models, p1, p2, probs_df, pathname, cm)
+        print_model_negative(data, models, p1, p2, pathname, cm)
 
 def show_results_RS(df, probs_df, pairs, nbcpus, pathname, cm):
     pool = mp.Pool(nbcpus)
diff --git a/Module/stages.py b/Module/stages.py
index 1fc8350..71222ee 100755
--- a/Module/stages.py
+++ b/Module/stages.py
@@ -3,8 +3,6 @@ from Module import optimal_k_aggregations as oka
 from Module import monotonic_regression_uncertainty as mru
 from Module import tools
 from Module import selection_algorithm as sa
-from Module import preselection as psl
-
 from Module import dynamic_preselection as dpsl
 
 import pandas as pd
@@ -12,56 +10,38 @@ import matplotlib.pyplot as plt
 import os
 
 
-from sklearn.metrics import roc_auc_score, confusion_matrix, matthews_corrcoef
-
-
-def stage0_old(df, nbcpus, threshold):
-    reg = psl.regression_error_matrix(df, nbcpus)
-    if threshold is not None:
-        reg = psl.preselection_reg_err(reg, threshold)
-    return reg
 
 
-def stage0(df, nbcpus, m, log):
+def stage0(df, nbcpus, m):
     config = dpsl.all_configurations(df)
-    Q, pairs = dpsl.algorithm_2(config, df, m, nbcpus, log)
+    Q, pairs = dpsl.algorithm_2(config, df, m, nbcpus)
     return pairs
 
 
 
 
-def stage_1(df, cls, min_k, max_k, nbcpus, strat, funct, log):
-    k_error = oka.k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log)
+def stage_1(df, cls, min_k, max_k, nbcpus, strat, funct):
+    k_error = oka.k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k)
     k_opt, err_k = oka.optimal_k(k_error)
     return k_opt, k_error
 
 
 
-def stage_2(df, cls, k_opt, auc_file, conf_mat_file, nbcpus, funct, strat, logs):
+def stage_2(df, cls, k_opt, auc_file, nbcpus, funct, strat):
     errors, y_true, y_pred, y_proba = list(), list(), list(), list()
 
     for i in range(len(df)):
         out = df.iloc[i, :]
         df_2 = df.drop([i])
         df_2.reset_index(drop=True, inplace=True)
-        f = open(logs, 'a')
-        f.write('Patient {} \n'.format(i))
-        f.close()
 
         ndf_err = cmu.error_matrix(df_2, cls, nbcpus,funct)
         cost = cmu.cost_classifiers(ndf_err)
 
-        f = open(logs, 'a')
-        f.write('Matrix computed \n')
-        f.close()
 
         mve, pairs, algo = oka.find_k_metamodel(df_2, ndf_err, cost, k_opt, nbcpus, strat)
         pred, proba = oka.create_and_predict_metamodel(df_2, out, pairs, nbcpus, funct)
 
-        f = open(logs, 'a')
-        f.write('Pred={}, Proba={} \n'.format(pred, proba))
-        f.close()
-
         errors.append(abs(out['target']-pred))
         y_proba.append(proba)
         y_true.append(out['target'])
@@ -70,21 +50,13 @@ def stage_2(df, cls, k_opt, auc_file, conf_mat_file, nbcpus, funct, strat, logs)
 
     acc = errors.count(0)/len(errors)
     auc = tools.auc_score(y_proba, y_true, auc_file)
-    auc2 = roc_auc_score(y_true, y_proba)
-    CI = tools.confidence_interval(auc, y_true)
-    conf_mat = confusion_matrix(y_true, y_pred)
-    mcc = matthews_corrcoef(y_true, y_pred)
-
-    f = open(logs, 'a')
-    f.write('acc={}, auc={}, CI = {}, aucsk = {}, confusion_matrix = {}, mcc = {} \n'.format(acc, auc, CI, auc2, conf_mat, mcc))
-    f.close()
+    ci = tools.confidence_interval(auc, y_true)
 
     labels, probas, uncertain_pts = tools.unclassified_points(y_true, y_proba)
-    return acc, auc, CI, conf_mat
+    return acc, auc, ci
 
-def stage_3(df, cls, k_opt, cost_mat, nbcpus, funct, strat):
+def stage_3(df, cls, k_opt, nbcpus, funct, strat):
     ndf_err = cmu.error_matrix(df, cls, nbcpus,funct)
-    ndf_err.to_csv(cost_mat)
     cost = cmu.cost_classifiers(ndf_err)
     mve, pairs, algo = oka.find_k_metamodel(df, ndf_err, cost, k_opt, nbcpus, strat)
-    return pairs, mve
+    return pairs, ndf_err
diff --git a/Module/tools.py b/Module/tools.py
index 273b80d..02401a4 100755
--- a/Module/tools.py
+++ b/Module/tools.py
@@ -122,15 +122,16 @@ def auc_score(probas, labels, auc_file=None):
     CI = confidence_interval(auc3, labels)
 
     if auc_file is not None:
-        plt.plot(tpr_array, fpr_array, linestyle='--', color='darkorange', lw = 2, label='ROC curve', clip_on=False)
-        plt.plot([0, 1], [0, 1], color='navy', linestyle='--')
+        plt.plot(tpr_array, fpr_array, color='darkorange', label='ROC curve')
+        plt.plot([0, 1], [0, 1], color='gray', linestyle='--')
         plt.xlim([0.0, 1.0])
         plt.ylim([0.0, 1.0])
         plt.xlabel('False Positive Rate')
         plt.ylabel('True Positive Rate')
         plt.title('AUC={}, CI=[{};{}] '.format(round(auc3,3), CI[0], CI[1]))
         plt.legend(loc="lower right")
-        plt.savefig(auc_file)
+        name = auc_file + '/auc.pdf'
+        plt.savefig(name.replace('//', '/'), bbox_inches='tight')
     return auc3
 
 
diff --git a/README.md b/README.md
index 9bc3c91..0f31271 100644
--- a/README.md
+++ b/README.md
@@ -5,36 +5,22 @@ Author: Océane FOURQUET
 This project aims to construct an ensemble model of bidimensional monotonic classifiers[1](https://link.springer.com/article/10.1007/s00453-012-9628-4). In addition to reimplementing an established approach[2](https://academic.oup.com/jid/article/217/11/1690/4911472?login=true) in python, it integrates a preselection of the pairs of features, reducing drastically the running time of the approach.
 
 ## Python and librairies versions
-- Python 3.9.1
-- Pandas 1.2.3
-- Numpy 1.19.2
-- Matplotlib 3.3.4
+- python 3.9.1
+- pandas 1.2.3
+- numpy 1.19.2
+- matplotlib 3.3.4
+- multiprocessing
+
+This code uses the multiprocessing library to parallelise calculations. By default, the number of CPUs is set to 1, but it is possible to change this configuration with the parameters.
 
 ## Run the code
 
 ### Data
-Data should be presented in csv format, in the form of samples per row and features per column, with a 'target' column for classes. 
+Data should be presented in csv format, in the form of samples per row and features per column, with a labels column for classes. For the moment, this code only allows to work on data with two classes.
 
 ### Code
-The code is split in 3 stages. Stage 1: determine the optimal number of classifiers to construct the metamodel. Stage 2: compute an estimate of the AUC score of a metamodel constructed with k_opt classifiers. Stage 3: construct the final metamodel from the whole dataset. The three stages are coded in the py file stages.py, available in the Module.
-
-To run the whole project, you can run full\_project.py with as follow:
-
-python3 full\_project.py <dataset> <probeset> <outpath>  
-
-ex : python3 full\_project.py dengue/dengue.csv dengue/probeset_annotations.txt Result/ > log.txt
-
-To run only one stage, you can use the relevant py file among stage1.py, stage2.py and stage3.py.
-
-Note that by default, this code uses the 3-classes classification (severe, non severe and uncertain). If you want to compute the metamodel by favoring severe or non severe (2-classes classification), you must change the parameter in the file full\_project.py.
-
-
-## Files in Module
-- cost\_matrix\_uncertainty.py
-- measures.py
-- monotonic\_regression\_uncertainty.py
-- optimal\_k\_aggregations.py
-- selection\_algorithm.py
-- show\_results.py
-- stages.py
-- tools.py
+To run the approach with the default parameters, just run the following command in your shell :
+```python
+python3 run_mem.py <dataset>
+```
+There are some optional parameters such as the number of cpus to use for calculations, the maximum number of pairs for the ensemble model, the name of the label column in the dataset file, ...
diff --git a/run_mem.py b/run_mem.py
new file mode 100644
index 0000000..c23dbc4
--- /dev/null
+++ b/run_mem.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+from Module import stages as st
+from Module import tools
+from Module import monotonic_regression_uncertainty as mru
+from Module import selection_algorithm as sa
+from Module import optimal_k_aggregations as oka
+from Module import show_results as sr
+
+
+import numpy as np
+import pandas as pd
+import sys
+import argparse
+
+def parse_args():
+    parser=argparse.ArgumentParser(description="Monotonic Ensemble Model approach")
+    parser.add_argument("dataset", help="dataset in csv format")
+    parser.add_argument("--target", help="name of the column of the classes", default='target')
+    parser.add_argument("--nbcpus", help="number of cpus to use to do calculation", type=int, default=1)
+    parser.add_argument("--m", help="number of minimum disjoint pairs for preselection", type=int, default=30)
+    parser.add_argument("--favoring", help="class to favor in the model between 0 (control case) and 1 (cohort study)", default = 1, type=int, choices=[0,1])
+    parser.add_argument("--outdir", help="directory for out files", default='./')
+    #parser.add_argument("--selection", help="selection strategy to use for the ensemble")
+    args=parser.parse_args()
+    return args
+
+
+def verify_nb_classes_dataset(df, target):
+    if target in df.columns:
+        tt = set(df[target])
+        if len(tt) != 2:
+            print('Expected number of classes: 2. There are {} classes in the dataset.\n'.format(len(tt)))
+            return False
+        else:
+            return True
+    else:
+        print("Can't find the class labels column. Configure the name of the labels column with argument --target.\n")
+
+
+def modify_label_classes_dataset(df, target):
+    if not set(df[target]) == {0,1}:
+        tt = list(set(df[target]))
+        df[target] = df[target].map({tt[0]:0,tt[1]:1})
+        df.rename({target:'target'}, axis=1, inplace=True)
+    return df
+
+
+def main():
+    inputs=parse_args()
+
+    strat = [sa.NB]
+    if inputs.favoring == 1:
+        funct= mru.predict_severe
+    else:
+        funct= mru.predict_non_severe
+
+    try:
+        df = pd.read_csv(inputs.dataset,index_col=0, low_memory=False)
+        df.reset_index(drop=True, inplace=True)
+    except:
+        print("Can't open the file {}. Check the format.\n".format(inputs.dataset))
+
+    if not verify_nb_classes_dataset(df, inputs.target):
+        sys.exit()
+
+    df = modify_label_classes_dataset(df, inputs.target)
+
+
+    cls = st.stage0(df, inputs.nbcpus, inputs.m)
+
+    k_opt, k_error = st.stage_1(df, cls, 2, inputs.m, inputs.nbcpus, strat, funct)
+
+    print('Between 2 and {}, the minimal optimal number of classifiers for the ensemble model is {}. \n'.format(inputs.m, k_opt))
+
+    acc, auc, ci = st.stage_2(df, cls, k_opt, inputs.outdir, inputs.nbcpus, funct, strat)
+
+    print('The estimated performance of the monotonic ensemble model is AUC = {} +/- {}. \n'.format(auc, ci))
+
+    pairs, cm = st.stage_3(df, cls, k_opt, inputs.nbcpus, funct, strat)
+
+    print('The ensemble model is made of the following pairs : ')
+    for pair in pairs:
+        print('- {} \n'.format(pair[:-2]))
+
+    if inputs.favoring == 1:
+        sr.show_results_pos(df, pairs, inputs.nbcpus, inputs.outdir, cm)
+    else:
+        sr.show_results_neg(df, pairs, inputs.nbcpus, inputs.outdir, cm)
+
+
+
+
+
+
+
+
+if __name__ == "__main__":
+    main()
-- 
GitLab