From e12b40fcce85a033d2a79f02e8edd41acc39a470 Mon Sep 17 00:00:00 2001 From: cbbcbail Date: Fri, 11 Oct 2024 15:48:10 -0500 Subject: [PATCH] Real-time loss plots during solving through solver callback functions --- data/Fig1-designProcess/blend1Subset.pickle | Bin 2574 -> 2574 bytes data/Fig1-designProcess/blend2Subset.pickle | Bin 2574 -> 2574 bytes data/Fig1-designProcess/blend3Subset.pickle | Bin 2574 -> 2574 bytes .../Fig1-designProcess/distinct1Subset.pickle | Bin 1131 -> 1107 bytes .../Fig1-designProcess/distinct2Subset.pickle | Bin 1470 -> 1395 bytes .../Fig1-designProcess/distinct3Subset.pickle | Bin 1710 -> 1902 bytes data/Fig1-designProcess/distinctSubset.pickle | Bin 2094 -> 2094 bytes data/Fig1-designProcess/fullData.pickle | Bin 3782 -> 3782 bytes data/Fig1-designProcess/hullSubset.pickle | Bin 816 -> 888 bytes data/Fig1-designProcess/outliersSubset.pickle | Bin 1614 -> 1614 bytes data/solverData.csv | 144 + figures/Fig1-designProcess/blend.pdf | Bin 18143 -> 18088 bytes figures/Fig1-designProcess/express.pdf | Bin 16776 -> 16790 bytes figures/Fig1-designProcess/tune.pdf | Bin 17396 -> 17669 bytes flexibleSubsetSelection/algorithm.py | 14 +- flexibleSubsetSelection/plot.py | 58 +- jupyter/Fig1-designProcess.ipynb | 14994 ++++++++++++---- 17 files changed, 11766 insertions(+), 3444 deletions(-) diff --git a/data/Fig1-designProcess/blend1Subset.pickle b/data/Fig1-designProcess/blend1Subset.pickle index 16f85c838d0d11e5a27fb95a6c8811b3526d9470..09c09e8c57fe9176dda0b498089e9911350f8b82 100644 GIT binary patch delta 1884 zcmXZc`#;oq6vy!q6XP<28AD92yNN9a&dd-Be2FnWW zR2Sh|6#M$@=YZbGlVbDP@5OnH@eQ`S)FHj2$5*{a2b5G@b4DIb5$C5rmkxc@23nHv z_{hkgMAx2a=6_fb!r$6j^{DiV&zXl!%y^;*Awp@p#x6DpWA2*z_i9K6&AiMCcv4c8 zR2{UoM1g{9HyGW!Xlk%sy6@@>cRgs|35OB~w4qhOaBOFz9&FpfbV!+GgHgGt?8E{# z)PMZ6e7uVZgUkaKYnn8{xMP!zLzg!Eu(q-E<_&E)U-G%Q&6f#9sSjBYAtTRNE`4qb zIB-4Hv_!Vb5VB1aV{*0FFr4lo%&nk!Ft@o#3DyswVR z%%d|QT$LvJe*3WaiTujSgri!}tebkTbP*eVY6_1K@Mw~a;h85FQxUV^fvB5=tZg9< zRh}{vxiRF8!KSma55$?5Clci9!^2OCs|CYDgm0VlJV94Vw!bW3s_fT;4TZvB111OL znXnZ3ZB7>THB5x^x z_xg_0lwHz**!xaM@D={3cy`A+W9whk;HvMkbD{_{$m#R%E@pFK{=Br;GdC;4M0C*8 z&Os?L3>E3eO{&9-TW&eBXek+Xw4Us=ZYAS$dUPcvGXRE8T}ZRJELM4K^)V(+7dY`& zWT;;e7}_6l(+{e^yFGPF3cj#mL1_e4bKXfNZo0fT_H8&*(zWCmw{0#HqB0UQ8x<$W z-iBVIi^r5C?SfZMEiUR{XUDLyD*T63RWFq599IB=yQPK1{tGFPyQH>RvEfa~rRJ1* zJaDcY;fGF*k}0|JDIIqiaShe)7A~45uWocCH?N)`r`u9m8W&HIoeq>mYHXw)_&}sXFZ`7*Led8CpF#HA07MvXG@@@rf)i+^TZBvsb+4 zsraS)9A&WnED+i6nIv#a?|8)BX%c&|fLl>JOd>6!hNrJLiKDL@ZacDGPP#H%e_G$g zg@D$c%}(6|;$W)%z(!hEA4xy3?BrkPUXXA6eib?}=#qFrZ?=WeG@*M4_Seufz&R_e z#`r!1dZRNPsl*AAoZKI`9L7jf+CbLAeH^gfqULA3QUwx{^Qpl4VKU>$P}GTI`cRY{ z>hi}O15o;`$}r{2$mSbmccaQQVamDT&bYST(J`nBR9hn_{IM9@*gZp(c)FAA zR9P!0H)R*qT}wF9E^j5ZSR-1(wc>w5wf z8f8af>&e4)td$R5D?xC7ywR?^Z;1ayW8K&yEjaU|TY_{_Mw0uJci3CgK@!^8m%pNs z#MD`t*MkXV2RF0ZP3N2BkF`Yqb}$Y)D>Nd5){y7sN4T;qtQGtc%t5@59*7q zLIcn>XdoJbhM`-~NOWt~4i#N$2dBNyN`? z?|s=9_7zFIIpM<1EO1&Su=AM1fgIy7V{4gcE=y;? zM~f_KayT94-+ybZTk}mU(=-V^Y)0@PWFoT2aEJ}#K`U1nZstPyR8onenhcEvcm#Ts zC_?Bn(*5GhM&zE6UQ@7-4@-+9q-j?vpyaw}xwVlpjO+N;s9i;&ZC)d)2dUOa=&>Z5J^I)Xm+(l0_br5uY21{Z!9jrQ^+OiW_aM-et z(Rlkk@*DqRNv5d)PdL&I1J0l&E-Bj?>8}9TPoCj9>z6`aRDgxO;|8ItD8oh|_bh+EbgrLl>1aTk( z>XS=M%GCs0Pzomu-q3Q{ZxQhRd6BL#SQhCDhC1fc1!-*7ZVr^~P1A24VT4pGw_SV3jacF}#uiX#;=8 z_jBm^1ClY|*Ss izvp6HlwvEemDnn5HMS;ozv5hSed_ty-ISWExaU6z#9x;H diff --git a/data/Fig1-designProcess/blend2Subset.pickle b/data/Fig1-designProcess/blend2Subset.pickle index b7bfdfdbf1dd14f18a1426373eec1fa9e28b883e..f3d08f4b69e8864c645e45585a54a5a478c24d92 100644 GIT binary patch delta 1815 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 c!=V^kg1wBrg1w5Z!rsExV(YL(ZV_$!ez>% delta 1883 zcmXZad0fnS9LMpgX=<98YNnY+M7oBEL=q|A&!!R`3LSFPCX|#USK?Q+u4E zs0aTTY-c;%7DBM;+}6~_HsZZISG>n@faI+@!P^+kfSB4@s|`N4(XkE2olgIC(|hZ~ zLm$=Y!11xI{DucZ1ol~M-|E~!+HM;z@ZK#1HQhmN!)rYxp1XJB_aHvpZgxzHn_o{) zn9w8fl`$yro1EbLQObhfsVtj2&I~x&-d0e*>l;aIe;3d))JvOeIwLTpyGdPXctcy{ zXX3EH$i`h+0FAB2D-SZB6EY?RC2yZwLB_#f4Iztw)rgbWE_< z!i$=~G%2(7uT_Ta>-}PikMrQejFT+s7K#HCs$W>^SAC&34s6Spbn!v4;kS8`721%q zYDwwL$Uf2^>>lD?s18;ITZhw5t3cb))8+9ynGoMz8PAt0gJRrjd9G<4d041QTTar1 zWj6*g#-Eo!RN@5Qy6vNZpOhVwJfn$L+rNZkXUKs_wJ}`+3n5V1g06hZj0?&03QHFH z8-g!goY7eDgpRR1&#NtcLjn|^ES1CrJR#%fDcxV{7FAA%stLoW*K2y& zb>4^#iv+9oQD%u6@T9!wS?@X)%-r;;tA46F6hVJof2gxz zfW+Hsdc=1XVC-FO+2k5XijO%QUT)6^UZ6h3^}M78a;NjDu~}7w`C?b5hmrv(zq(N2 zm(xdfYJW<7rO*Y}EqN*(AeM7ALq}eUAS#UNDatTa z(0enyub0_(k`762#=Q{^yzC)!lE?@N>~)>S-9HYjxsPM~hX+ZA&wS<@V>R&lcFq22 z4Ij!c*EI11hshi_mn*wp2;t~jbB31@3nuyo=tlE45~`AZOjwgGoL{Kq#`m`vkXLQ7^{Nkro0x-z*ykaML zMO_^Ijx# z5rI~5qy6i_iLk&fRej544iC~g?!>hVIPwxBRk0GqWc)f6l!bCpO;iijMn$L&Dn@lt zL(~MFjGCe5zoZy5Fj%5is5LqlwL|Bj1O?Oqbwr&}7t|GXLl^(_#~cp~p6F6^73zaD*nymaA|F2!P7Lp1C?i=$*<^VIk4Pah{v-@ z*&&e2vSQ&&<^vBVUMq`zAm*SFG^x*=ll6evcaxN_`}iDcTjthBoc>_noinK*+KkQN zkJZ_|KRq}cI#+2g*JBcO;Qy$(^7GQy_8Gg(RMpINp4q#6%QGyfc(;Goj}<(&YZM*g zdc=%uzyGv9?!1Gg(N6-ui^ zX$>fC3#A>Qv^$gzfzk<3Iu%NnLg@x5JsnEVgwnI2^gJ*v%)qc1DzF?%ubuplITru} Cnwj(f delta 514 zcmcc2@tT9Bfn{pKM3$$FA`@Sk)H^UTFw`6~i&J?0YX1|L6h4V1pZ52>d7SX*_ow}8 z2k)56?f$y|N0y_VYP67p&&=t&m*y)t<$JCJ&MkXU$y5@(YO~E zDd3Rw$w!~NP1b?s%*QRFYXlF>Ix*Aj)@D_Qf76dHmOmxoa3}HfuGd?n9M~S+-NkRg z>Y$TYZ10i5>#!;G(cEoSoDL-_Dvg&i86CQK-TH(QKk_@gGwfKEz+FUJ9kR XfoW+5hFwsBeNg%cls-238FMZGYTTqe diff --git a/data/Fig1-designProcess/distinct2Subset.pickle b/data/Fig1-designProcess/distinct2Subset.pickle index 3911e274864d7a2ff31676b4009c8697540d25b9..0e1250db284d36f63999d71aedf7e81556c1733b 100644 GIT binary patch delta 762 zcmdnT{h5oUfn{pOM3$$F@)KW~)PG=PU|6Icw93w%%|T3am9J-wh=atZi>uUSU+-^? zobX=UoZ&!U-XW#nXS@eoGc0{_{dpW#p73#b?(@R_R*^$<<4Ylj5GmovFI`FwPM;nh zI$6tmU`L12nje934j+14`(|&Earj(6MWWqPm8%b7 ze9q}mb}21AUxwj8MBjt;*+F0S&(n6~;dsyGz>vmhmKJbhe~3@_zs2We94gn!EY%Q| zbzr&DFCOqi(Sc3*YFLW!C;KW@kM7@+!VVdcR~~2VW_0k_8y~aY<@5fHzK%;Kq$@kj zcpm(4m9UtD&=kGZ(oA3M4c4U}UTXPc|E0C{l?6}J_zq@)cl{VWIg zL|LEIq{}(n+j+a?O6V{9EyZP9(w}^^Kld;1S#GqT!*X{a9?vFa2V3b?=YKzAbC@yV zp}>l#Pxn8Vc&#ka+b=X@AjRmw3q8Ki8|Eh3KnhpEaR|a$EF(sOaAQt>~BAF zp$Uh>ibJ|*OTwS-zvg%Sg!P;6_BEz&Sbs!+-0$)&&#<84-TqxaR`A%aQFJ)&yo06W z)hB!Zl@lYbuN8B6XVqfsB_`ug(`m>b!zJP{rDRG{4@XkzWH086jPjFZSk&vCe=tA+ zGn8h9((F)L8cHibX=Ny_4yBEtv^kWvh0^v=+7U{-L+NlRodBXufH)Pz0D^o7#ZU^R jtD$r^lJJI delta 830 zcmX}geJs>*90%}w__;3U;m%`rc?j2G9(NVZ!|#)ao5qFZWEi(wQJ85{S`W_CkV!Zc zxm;|`Ln@qysD9^Rrr3%#^H84B+U!Dya!&L|-}V0I^?tuMb>A|uY^Ae3F#(oLnB-_} z0%CQj8>7Gy64c_Ruo?~C-7`4L6z|~`mt09gTOHs=i`b3hJq#6wnrbyR{MWM3Xhp!Cvn!%b!QH$804ipjDMbxGyqLOsl;vR7l#T)D;c?SBN8xs!*!kMr@rKq{Or#Sc#x5wYD0K z&`g9hm`LPMO8GBJJ31udPSX&qb0c9Ln?$9V&O3d-{GNHfJo8@HTxK(}>E}LEl`v+g zj*>-35zr`<%hreMJbalTUSj;Ql*9(^>Oh^f$r2e=vSP44r3Zz7O$TU9>w$qY+cG$p z2Fo*)1H~eBh>_Xzr`6`kpM|{V9(pE_u#$fBp%)h(q(IK;1rCf*O*c~dxe#Kc6TbG1 z1<2W1yF>45LGxD@*OWn~@T~BFsHpr74{U}SS0c@{K_U8{oA0kH-Q#po9+~iZIHEmn zr9}mVq7%9AXK#^99r2P11{-Aiyg1$MI?%Csu^|4S8l+SYj@vbH;b@Gc%qi9ov|5AW zyu(@G((a=)e`N+08xVO(`Gj!eRTLjDH-bA}8mGEF4524bbnl;>Y+d+em^5y+GyzKJ zt6^1{5qOWKYxQ**L&%|m?W(&xNUP^vv3dO=eMoHZfzlk(t^5jJ8tQ;6ea(*Jq9OHb zixAxKR*(ax+{(;kC2=#rv${Ce63)*BKd#f!2UBAIp7k&p@ggyNa6-O9&`o$rrpGw2 zATrFI7-6#DU2boiaFGUTQ~ak%Ck#M0l}{|s)8Osvv0Yd8D#`oxX`jnt*iu)?`11w( zZZfTJc4v*4E>$1x9A12fDs^yBx8qlB6EhLDLwRrVK!3Gqv+)K8+!|NCgzpRoi{5Nq$r$_1L#-MH@V%ULFb4w8R+?NWtF$;cO+BX`qt79A7Fn zg6uB!j_A-XqDX$~!dkQ$xPBXBTWb7-$fWp3ouR%U`h^*#xm_C~GKu+gKE#y``@IFb z<=*?Y-m9`yvM6}*s@7>9xLUZ%2 zF|Fz?QV~d$RXVCcO((xEHB3fkILR5xPgcmd7OPz@Z_N@d${G##Yv$09b+0ol;W7EU zS2I0z@!%>ESS$Hxv|bn3V58N{6f)2dC>wqPcUD3&vVIuR8BYuqCJQ$nNUA?c@Kac0VW3je(u|)~K2{{3IjKHu-}x9CWUiOXB~Uq~PPUO6}%p z!Vxcqt@w713>TLFlF0E;#V?*JocNRlyXe;hd9^I(xv5F((9x&l^psmQ7VuKigKeTj z%0o0G9aYkP25J*54A%-Ijwg;tIKT}& zOksyQX~#;^?l}Ej)ULIbJp)d8yV=;%LlkwcU~Jti`G&tj z6gd7oq!})5*4&A{OHwK_dtK#`AgO(Ge_7c|P`%c>TM!|HW0sx0U(05QsAb3Aq__yU zKSy3ULzalzt4QU45)143zv@bZi{vbc&kk|(!1vKxNzXo5Alba-?N8r{0=a3|jMq&E z=8toZNUO-%eA^GH zPGa9N*3wzM3}`$uTB3bOj!31Zp%3WbZ`KtI7Oeu!wu~zN^b*+~(J3}u^iVomTXgOF zZZh*yZHHRMg@JNgs&zHP$xzYPsBB)U@4b@w%>Fr2wR`Je(73dP$j_|urSeC~9mb;3 zt&4!mgPBUbWF^Em=ikao_>*+!rqvhMFOcQ-VcCPl)vzhcyzFq702-zTOj9DB^HxQ8 z@_f0QGOL-t(^JeFScwJ|o%a7&SRrUA8i|V0Bs3XagRVu>(F}A0Do3}VTWK`IznP22 z+h{&oh!&wrRE>U!9zqYJ6{sGqK~3m!^c1c1zdDV_7w9Fl4Yi@yQ9Ig=_M!c#3;o_q H=j{In%UNOn diff --git a/data/Fig1-designProcess/distinctSubset.pickle b/data/Fig1-designProcess/distinctSubset.pickle index 9c882aa88044a4e942ed69b657322e402ea7d00c..934cc4bb75a3579abc032c1187f975adc29be3d3 100644 GIT binary patch delta 1408 zcmXZWeK6E{90%}S?6T~Wwb^ACwG!^eO5-RGeLvcb&19D4?&wyk%Tsq@HW^B{E?c)f zc}lLLu3YZqoQKrljDCxX>bP>4>N->&3t`>1sOxT~@B5$Eyx)JlYuGjHIuTi2?y9KT z7(xa9{KG0&hgU>r{h}yeVMIq_3SRSkNxCxH;&!k7bZ{f>-rLx^j7FCAZ4;MGATOm| z6gkGweLZ)e{;7lyPgIcm?IZ^V$c_e84SID%PUJ}+EtTm{l=(T}Yg z9-{*;vJ=a8Hjot4_ado<46@cZWvx_C)Q1IKDM)mN8*`ksb`8^L((cI60M!x}*Sz5A zs!f1XEdE7cvVgeh9%yF56lk33(vvwBu(l?#qhf=R=>0V-Z8U+Y%jzC;s?0ajc?;4i z$}gJ%a|LBYot@|iPf`ar^!w8x^@RW0<0>}H+mtx1ky*iD^Iw|2PnS?i$i|^u5et3} z;n24nc7_Pc4VjlGO?40%H`2Mr3<3pJe=LttL6dmSr-HR^EHB!qnTj@t<{|ys3ld7vfjK7~gX&EO;KRKb0UZ5lo|TmCqRu zku7}LT-Tml$A-6l-K~o<3+UOEU2>$uK=^DwtKHW{ffVZNiKz8V*d$de-KV6s;8zrL zes%d9_rCEi7$tzpJb6BueM z1l_Ko@eA@El+xwl+LgeE>|MJdkC9@)nJcek6}+?3$ex666`r_=?B-5e#Ap9wgGzs+lp<&cARcD-~S(wyw+#{ delta 1408 zcmXZWdowLBkiKz#hV!3nQ9R33IkJ0^()4#MiOM`0XD>E5!(;@udL`sbSW-v3S! zy7fKc{>EAK(AXy2XP*i^81%|c^XMf)zsw97&C!73@v*Ajm6MRdmO|gin%(D~QenQ`Go)3(fHLda)gyTfaPD+DHZ(Vl>~G716LZNx<<&Wd zcT-?(`wK_2<`2Xt6Pwr+I}XImeP79+WWnq~H&^~Qx=5S zuh!M)G%n;8EN~WO22dbbo>?>dj@Wj2e><<02GR58KE|$t$ZW^n!d~f&4y5K~mdiv0 zdZti4S4U~U<|F@1_S&w1+reh?4|09byyCk%j-?HUwHAifYwEOBroVC3mFmH)ce`zg zAH6NzdFR{Tok+kJJ8X>oL<7>vJ(~vnB9L~38B=tZ4sG5Q`Kcw%i25SAD1dAMlvlSK zLd&L+Utag3)HH7rJrSN6jZM~p2Bsx@;mm5Vzb1(P)$kco{&ZNdp27sBW#8Eo96C&& zwzxKEYXqCN=^R>qsRt(u#hrET@6k&Y+M11)QH0uW12e-E9GQQlgfGscpr!lne|4}x zQQtAZidaNj{e4@Gzu>@yNIO!Hl?JQ}kx02Y{<;93krxjiFo5Uc%v(vPwSe|mCD*TF zw~ZVLP2THb088AWuPPtWpy)xN_dqQlBK}1mJqpJ zRv^9Do5dNWRA}?pRL*RuCTfC)OB6{fVDO8j`T9XNkQhk0Cvgag7Npms%_5gk0*{y0 zdw>jzyB}INl+q!_SkqR9Odvkc;TUsb8ST=P#;>#1)tEuzgAErt64=l$P}iM(y%Ow#<9sKQ=1`R^dnns!0+D)@_hK8U5PPWf z$rRNPEVdVkT3qH< zlse$H4eNq+#Ud1>e-DJz-v9sr diff --git a/data/Fig1-designProcess/fullData.pickle b/data/Fig1-designProcess/fullData.pickle index 29b4a65def88b7e4828d72fd40e25a5ac4b9bb39..26859603835d3375e18698aeb9c2d9e182a73af6 100644 GIT binary patch delta 3238 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 delta 3238 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 diff --git a/data/Fig1-designProcess/hullSubset.pickle b/data/Fig1-designProcess/hullSubset.pickle index b5f796eb8ca186f42e11cbe98c4f0715bf0ba928..6c7bb274234887de9a33369d06c36d9bddf2a92b 100644 GIT binary patch delta 269 zcmdnM_JfV3fn{p$M3$$FToYfJ)Gt`19<<8Noz0;&a>9FYbA|)AiX567UkW)~W0d<= zbWXw{L`pdFOP7+vjt-?YKLX_(KG#o?X!jI3z;dNuJm80-gU8co-GM~x_{S?6+E_U6djH`?_eo;^~rv6KjTeCuF0898eRbmP{0nQ c)uFTols1CWwouv;N>7B+v!V3j$%mP80bV9nbN~PV delta 210 zcmeytwt=R#^)EE4it@1lgUfO}(pvm02n&UuTiOGfZbYX|-Hb-udUVC&#`VwQr#pA~K~|CX{HP@BBN^XPFEhZCC*DGgX zX}Q|vJoF&v^cyph6Dbdc$Zpe18Ce#*}9pymRrNW%i5 z&`}Uv`imr9Z8#gEX`|B1*8~b=4$v?$xVgy2gaw}Zr^8As3uGFlP~wWr6?K71l`(!&ey>)w)+R-DciIWi3^qg>R!{$oHIWNoAc z^ira0mI|S5h|DlL-i?16Ky19>PrPyhe` delta 959 zcmXZQc}SCS7{Kw(cbmTY=2p&fjq=EurAyMV71i$>s((NE6QXv9xL2|pvD+O)R8Tz8nK445J~sWhF8xkAbdNnG%iY2ES*7OrYd&Pr z#))b^U(1#~i?OxX1aNehZ+fqq3yCt_joPl+tktjajb^>wQahY-j9Ddu7j4YI+#na$ zWGyrsLmAljGG@pe?I4#}mHLBhA z>P=#}c~i!bcG57ydbM2pCV{lHF7G|M0O&s9e)Y4S0k@$~w1eWXy{X|7J;T$W`SOZX zt!%RpOjglY!b&d)7D9W)`bkpd)7tms@>BBo4%ND(SqS$1YcCxr7_~6nE=AFGA}C33 zI@f8XLEdx0LuM90z%@5oW1`rq-W+A^tssaJhMZI%_Jv$U`8k8D2;BZkR11|N*iy4C zw0}$h_sYq%_(#9UfR^GFe{%TL7${e+mdlw+fV!bHIvw>wz0p~y1ocIO&;@7+8j8x% z@F}&NB{-I%3KUQk8ij5^W6+K0CUh$rhsL8j(Ou}?|56-IX1<<3%U_2(AFV{q=!5(Z G{Iq{)@i@u= diff --git a/data/solverData.csv b/data/solverData.csv index 4b69f2d..63126d2 100644 --- a/data/solverData.csv +++ b/data/solverData.csv @@ -107,3 +107,147 @@ Uni-criterion: clusterCenters,greedySwap,1000,2,10,0.13878262508660555,0.7724079 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.1945001189596951,0.0 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.18785801599733531,0.0 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.234673575963825,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.29593419295269996,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.11445782298687845,-77.13353928048035 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.5462852430064231,-74.18261659032585 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.019615472992882,-39.956777992395615 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.961098090047017,-71.3535755814987 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,17.308373406063765,-76.92932448798969 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,16,0.10311844199895859,-36.98853938692782 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,40,0.3425103520276025,-55.53023413167705 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,102,0.7111876929411665,-77.72499108526614 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.17156568495556712,-107.85032842123348 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.009137309971265495,-59.99163302732708 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.28689464705530554,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.07565713091753423,-76.90150167654883 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.33772983809467405,-82.65893651396253 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.733736847061664,-37.72502949783789 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.34970149002038,-79.21528178454805 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.09934757091105,-87.1484395780551 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,21,0.09933742694556713,-48.916226463106035 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,18,0.07778958394192159,-52.25319459589197 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,92,0.4698902699165046,-86.11815292551535 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.3114050959702581,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.1782841000240296,-94.00493289823834 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.6240650089457631,-81.66286493321189 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.76467304804828,-36.356196781059154 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,17.084750175010413,-78.89219470658081 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,18.41927482408937,-86.71818903727858 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.9344452220248058,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8697499780682847,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.4994492910336703,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.4910243459744379,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.4479509260272607,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.7013822080334648,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.7932263310067356,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.925686597940512,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.9141074389917776,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.9515322380466387,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8977055459981784,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8896270530531183,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,1.3545968279941007,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1011312199989334,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8075686269439757,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7807131060399115,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.9366903710179031,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.150744732003659,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1362005930859596,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6776644670171663,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8283384050009772,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7767721880227327,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1211024429649115,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1975002819672227,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8234556920360774,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7040190550033003,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7956955870613456,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6690607069758698,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6585186719894409,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6739458279917017,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.39736516401171684,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8139416560297832,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.4658096390776336,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.5328066080110148,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.40911367000080645,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.42375491897109896,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.4381504019256681,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.0618235199945047,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.858548079035245,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9225411330116913,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8708883179351687,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.59070663806051,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.6839401100296527,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.401693034917116,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.6874031629413366,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.7578133980277926,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.5088547869818285,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.169300428009592,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.232280447962694,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.1939020979916677,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.139898219029419,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.007311812019907,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.013121727039106,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.9959770779823884,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.232953047961928,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2974324349779636,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.105868001934141,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.038483888027258,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2182905660010874,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2297344179823995,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.181866207974963,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.459757408942096,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.0248638410121202,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.8204639760078862,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.1470516480039805,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.907505503972061,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.873534856014885,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.7429639380425215,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.8942721990169957,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.134770376025699,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.9120049610501155,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.98742147104349,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.976412029005587,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9450863489182666,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.081287116976455,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.7693268969887868,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8417827270459384,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.855016679968685,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8780118320137262,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8611697829328477,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.961038665031083,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2737037639599293,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.3527815849520266,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2911710800835863,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.5750179030001163,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.1241388369817287,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.108717106981203,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9237201779615134,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.1779711049748585,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.0755136230727658,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.065400000079535,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2507090859580785,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.2701174030080438,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.5799345769919455,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.3197142069693655,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.446158067905344,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.5796150349779055,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,3.578337203944102,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,3.711465527070686,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,4.2906140179838985,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.549799660919234,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.06814886396750808,-89.60162497757574 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,36.6902008849429,-89.60162497757574 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.3224127379944548,-79.90049127593495 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,36.83346623403486,-80.79567585790252 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.037519195000641,-37.37670531499123 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,50.97084774100222,-39.22812364018983 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,53.80880820809398,-76.04688048633925 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,53.854620625963435,-85.06005136858656 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,10,0.04771749395877123,-38.18019263929493 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,52,0.22991829796228558,-58.48640809913543 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,87,0.42976776498835534,-81.60528780506851 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,23,4.512196074007079,-47.91799174414664 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,27,5.162200314924121,-55.62985637521753 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,88,17.476347186020575,-81.49231730696414 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,19,3.7761652149492875,-46.45876245484051 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,31,6.059022648027167,-56.28867409761743 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,52,9.988744632923044,-68.26740153361762 diff --git a/figures/Fig1-designProcess/blend.pdf b/figures/Fig1-designProcess/blend.pdf index 7e08bba4ae96c54288f01e279ff1e68b45a97468..7e849172782d35df034cdf57c8e7f45026a4f1f5 100644 GIT binary patch delta 9145 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
)@pGMRj51n3aFg-) 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 delta 9177 zcmZX0cQ{;c)GZ<*5|OCUy9lCpMvX8sq7z09BD!GIaJ1-s^qT0xh!P`uHyAB???kUb zBFcAu_x^M5m-*v7@3Z%Q_u6aib)GZD(YTAzxD`lTAl9nx{kmON&dM|8*0mk%&Dsdf zH1Xrrk1vQl%{?s)&U!Skack7RSAXc=>UqSAC1^ft?f#~tVNJ0kvtZU4PWDLJd+~Bb z?B=|-<$B=e;_PSa%~5HJli%gmB;b8F7FeBZktxTt9PJFn9{x@?y}58X8a?ML*s$Ke z+&PfB0qn}wy^<)sSI^5&F*jGo$9#N?mlVL2dhCvbRwR2Y_x7SIA!@^Y{7=XC_G0~= zSlR8MmMfPdtj*C&pYBjU-y2eI&zM?9zwXrmDrdrPvm)%d6G% zSf^_)HN_LI$?C-4Z_(`}5VTSGkFQZ8@RpIV&tuGX1oYK|M|)kemyxl1e9f1*eDUhR z$|^_H3eBo0eZp9poD$=@(}@w!%ZtAlF~9@jcXS}j0}u~oPoIw~6O$~6PKvtFy4<$_ z5UNAuhecYprLmJV*@%1^K`DXc(6A#(TB!ch*vT^K?MQU#Yxm^q$J+vD!SOzc z64T)fYQL$m2yy+c6@9ML07aMGn)9%LsIJuDl>W*?m&dZwUyZz@1&j-GqOAM$IZHMe z7*NvM5&FA%1UpOXkLm5>CawJJCxuL?Q{M>~NC8PH6Go+R5v#qII(@CM?v>1J;Po0; zUP_3v%-#COBLoca9FZmeXOEO)C$BAA0@TcOEZ*zvo^r3nbjTcHxI;^e0tW_$m)~a^ zHF*>7KL6W(wwpdGXqxa2`hA=;>*T4r{i4Eh(}45lkfz1zp`u;vRCZboWW%Uza;^GS z5gFH`Zri~#7D{JwA$Jq)4x}oK9?VjY7>6E4 zb!@B415l>=8sv49^dBNKLb=DsuK0&F6YgnW!`qb0mn!;yt9;O~tI`(4GRjuJ5B4~*r?t9%irnniIR_?Mmm8DD- z^8N>SWH~iFuL|2^d)O-i;FuRFTLjbP9Sd#Ydx_4cCY&HucvY=T8Ya- z^RTo6X=U7?yFomR_Hs{D0F`w5{V6>pEK_g@+>m&C=*84SF$1&7f0$- zKGBVQeA(I~0*k>@_rDVM&ovBV;gT~8;Z%Jsz%13CncR>d5S~hiBxPH@Wq={)^AlEA z=8rrelX`8L%|3fj=-P5@|4=+0ANMbH8@4#_H4xw ztE;quu5DqWWIR4bOCk@UJ!140-ds~hfe&R=Pnt^Ku&h|GEUQQ;S>aenK#9E{C{%ox zH4CP%55MxRiB5nPH(JqHiYmw?;Q#&pT*p3=XRxYdEZhZ&$*)y>Oze+KS6%a=!gYFY#mtJ5vV&~8*+xl0`_;Y5&qPee(5T-O zocRkRHERIdTUBQX}$e6pdcB-PRyAhM@N#ar&g%T3EW*{V9S}?al_HN4cwZm zi6IQ>iYMQWe0ld~rNeAm0T1bOc*M;4&f8nPuVCq&^n&Fi%OdWJZoTb1?(YIJ*Q09J z$*q&=MBQP?FB(HSRU8NKGX1PF@^=gY5p2~0t*$*`Z@K#8loyD2o{kpkn8z&|%5qth zOtVM}mGTcXS^*8uDPU%WqPe`J7C}>kkGB-43-F{im{yU7%4gig0ScN@(b#epx4>I? zMsOVp&72wc5x?Ej$^45ZBrY>@jV*v+cQjau%X`}>B8;%<(a1PHWzvpqp*d5As?ExU zezvU3C+0A!w2bg-dp0qWf~Re~0tE@uGy4VeQ7X9jDL|`F=dbWdd%=j_C+}TJQ(y#n zFQ-19qJ5TeFPXz{r+i>FMBJAt1?2Q1dmip9laj|31W+9LW6RW;t9OHr+0;V=a&H+^ z%aM+X80llZL{w>0UD*R3j<7~TJ~-zm_NGQ1J}R#LsWJUPSA;tQO8j=?Nv$RZnTl7S zDr$qqVFx0<;PG2clJp=Z!F3#EsRy8 z#L3n3)VJq-Ro*$S(!ltMw>R3B{tQ?95v1KI_&GlrmMiN7)9(CP}62 zYAA_9(8^Z44%0(T)B~ZTge|7{cEZPF_`HqDWI_OT=9Tg7W9M8X=Zf(&?WqWtG);Vp zpF=FYDp2DxhG2E7>8_}IR;*=(l&08G>IQMGTNk_ChFQOr>K5g-GErYp-6d&I-;F%g z^%tVKui4fjIMdg|45ss`;@%zqR{iy)pClrkvL%~~{cizfc)M|pI&MDwoSi!x||&!pG)2sxPRo}$$Bb&f7*qthMj5EvIe%I>7Bh6 zyD1i{Qd2Y%=569z-)HX|AJR_>H@;u9LL?``jUqn`Dm(6XWZxVzza0C^Wlt7^r1cfTLT}IlwmfQQ{7B zzKxJ(C`p7~|7+pYW#ei|qED+La9@sz71KxeLZ*u|m3(i%yF(G%dp)j_-@~k}F;m?C z2}ZZJV=MYGZv)qWn5~YGL9VJ}@sKg&k#XO8q6j2$$RLR4)7xbN5{xk|LMi7u@C4vW zh*0}fti3Yc+ECWq&!%B3cxcYSPI^JGey7LWN9Rw9sz_C&O|tbs-<4W)um0ml2lq~! z?P+p{nbTJBvewko0+h@enaZh^)9^pNfR^zaEs$Ag|BA* zOP>2>Y*d=ihPCHOfK(rUlt>>*d}$1r=QeLuUt|_d<9s?J_d_i!XN&X?kKJOiJz%qI zCbW(gx`z5#J|^{g#gSbqG%f5Fp1VPF>xGC9Tu{5tP1wvm<3-|db<|)acm`EJ9@}2Y)r1J15-8%U=`C4>qe_Vj zI2a-uMlz}8*XpK~9-z9X(>mm+*4jkhWN9dTV~=ilDj#Yx&0sD{aXU{thRjh;PxC2p zYnl)~LVmfVf=KCbPOOWO^I-xMkPUx4^?HB%5B{ma82|b^lt;egUf%Q1cA4*ENBvEH z*QsSEHbE<@w>@#1f;S3y0_+^bHLQm{%cP_2?OxiF^|#1~VwHU2V+FsSJrZ0^r=1Ra4sJz%18t&>*CU zL9XWIEnQrBMsbH4ZM}zGx+mEu+5V|=Zp4pP2u{~T>eIvCSlHr5Oo${T%s1*tL5}V3c6Cq1HCa`a zmiqi&9y@DcL`%ikqcm<5JLkSJ$&@ZjyuO>NYxR!nn=MJzw>=fjBsUqTiDCkczq*Kr z7NSKiNRI1}KM2XvOc)3o4z*$*r&StlQ9NZtLP(~o zls3lTwHL>8SgHrPxY9zeb3Ou}tmlVM) za;Fk8T0k!4!tr8L^`5fifkvDs;hOjK7+D{KNaznYg%{8-c3syk_#LLrm&Zq;m{}B? z+1_5Crsw6KJ&e;L0GwaR{MhkP>u5Vnmloc9BTq6aYvOl3j}-%0e|vs7=Q~lD@wmA> zCW*Z{+d7cB`dcJ>4MT{}su|zh_xmfB!;s^5v{jpP{cB5B<|_W?s!07N6!`lr61drF zx!FC6jXk(NTmRZ(5oG#7^h0fX)M zU5o-B{)7wmsy7T5z+Kn(Xz1eq;<=U|+z6jAOx9mlqHds*we1g5F*|VcA%8l;BQ?vr z=n#&tag9gR_>=4V(PdV3KCE`L_jcg8v523m^7Hr_&&`wm1#AR#fL)eeU`73PH8PYMn}N1vGDWHf$L`e&srnYma2y=InfZh#4aO zJv%sbE<3T#b<2%aS-1NV>;G;NGHN^B)iV5k78Wc7=*|nIQq#DjPAgwKeW{nxo9EG( zC1cXB5#+1&d-!75&G_L~U+@sFYjg46{^-9c_mkH(sa5lzoYmSqgsMS?FVYa@n4wUQ z1t@Ckb1((X9d=@0N3rs3>2LZ2!Z)@ao}};kpKUBO zbmblE0y$S+5aXaWUNLkd`-kl7=efW41aWo)sakeFxxW3fV+$14mz`UG*;$=W+xE^M zgdu!1b2rm#8OPu2m?o_xf1&$UiQbQfiVdB1=W}1T%pb5b2FRX#3E1Aq-LJNxXbmOJ z$=X?#TqImracFa+a;mT0`|!^Bhp=l?;^b^27l2x<D`R59bykhQH-s8bx-ET+j>X5?fuBK`WTA@NU;B)3~ip7{G$v^7#@c!>;9oxm$kL0 zvpP?{NSJuYnm7WRy%hT+>QfoDcL%EHPxZ|wgUbS16GkgkCTk)BFP>N6&cM@L>dPh6 z3&3w%@ZA!0qW#v(RDCjsR)<7WR8Q6h4~mPptzM08MHpdYrtxy{rJH<-e-z?s*syM$ zs3@h0#&}D*mo`+=&WWlaF*>~|t58pFuY@R1r2SEOzi9KRTkULPy*_!^wtFE>iHp%O zk&<%><9D1>Nqh|y?y0Z}Rd5lF;F*9;CD8p*od2!9Q~HQ~zhhOUAyrdvxYrqusZX}< zqWz

2{l=y-cYct?!%fesr0CC@q=@tRbs4KwIUC(|_5PNsqX?AM)T5mCm8VhuZc^ zR8boA)J+;*6TsHJ{To>k+}5;ck#`;C(&Z>?e1dnR@&h99QiPBjzklJPpmZ+NR|lv} zM*KD&xQ*p>^spMr`MKY>9a4{9x*1+SeLnVqJf&=-tzkX^!Kmt7FCB!7wGRjtEV|zo zMKFJ{WTf+PsQ+>os!y0}^T=H*bOpv{RrUG#nB9F#(z>sk#P)vczwWfhHU$h3RT}*C zt5Mw@y1Y1Bx4UV-2fJ7GyS!a>o1zJbtXR1A{Q+|Zm2=Z{`bR6t z_uD+<4*n_6EC9Omf$M7kW>5=w}r$Nihz5TPm1|aqwzwZ(UZ+$4XZES-qSB3%f(lk;+py zx~-{t5`9TDeJmJXIp(2ru6sSbUTrf7BR#QU`a9&2s=)ZmDYob zf($*^b6HZwIL7!S#yFIMS@Z(fQ|>3Ihbc%*tPF6?xA3W52C1F&f*UyZKXKklj))nl z954qtZ`WtL?Yig3xYiEeqmZNNP)||}${idA zsLezq$IM@1<6}@$>%=GeQr;t#wD%-lVjM|iRWYKJ;Bp-|0T3i^ADo5?G|}Hbp#R{B z-Xj7X9a0G6jWkQwx%YSo%1bfL;kBr!oi@-JV>Bu z6(n$f0d(od2{5q_8f3nG547q|FDQ$tZ(_{6y9;Pv>UA*IK2t`J##r!Fgu?A?RSLDWpSG&2RYcL`9C!rQP zGctjiup3eV%gpJLYSpn7Lv5BKMF}=}KJjiMHNs3bwTK_2@s$2uJs%j)!414!^-&@M z>#w9!YbHDkSTy#Y?{8Z}M!k!(vu#{ctFvvY>q@N+C+sf91FVU?H|~Z{ZO?=g^Dg{y zHQ+^M_$xpLrng5SX=B=zVluZ$_!mFlWm*1e$3Xhhuza2Pp%_M$={r6;?tzJxV__uD zq!qmtd#ZH~^_>Y}-(*Mr9nq4Hh70}&AvuHoPV*5$z!Ds_cmFp!%kx&VRUNnYjKTnY zf(gXP!a?RRpOXqaol;=NVNNp zV$$j5{O3M;Qtl|InDa>E8*;ZSd1FrO{(h$A%jXN3Ya946M0TeYtDWY)ZlmikV_!XY zKizwpfWwC)*gZ&4d3iBLF|AC}D)EcVv{g>rV$I?N2{CIDfk=jy9WiUPon&$4f&=R7 z=I*x%vFFn0iP{b~_zw4Lx9|ZiTb4Q}0YmvTY$1+BwtCJ zm!ouRZ{t&P1@p!%1&z@$3mbTRe-idZU%`faFPdPyDP4n&i?YcYug~rV=jj}JCK)s2 zP%{uLuKbAUNvkQ6WBaZui4b27ttmHq1~F^Ga_S`=9h+m~QkmjGJ%)8q#!LB!TR!Ja z27q326~Vl$XW?iTW`34tz2a_%R(wQLO!exiK@n3B8Ojq@>2aKx$gg6S?8c3EuCYnr zgV4qh8}%T|BV}}>mw4Xq%ne__~;hT zi5m~Wr+BcDAjL)IoBU?Q1+q>9jvAhGORb%1OB&lwG{NgfpiMO3OQtkcFQyJKLsaNlGos%^D5e`54K2qJY6!?w{$NSG~wl`==o>Nq%w z^%t-c5XlJ6VmQ1vTJH1SN^9ph54N35_du{@fBY94`ZiSq+f@ji72E75?$a;x=kQEB#J?jnj#LIeuocZu0 z3unG!Fdn)$9|AHPd=d+4eCxl?T#|kHqM`2rE3MKUP^H;;Nx_n5+h7Kg3ljHJ0B3ua z4_0UKh=XF(HHI(PQh4NgyhMPB^g^(N#%=$%Q)zGG(ISKv8g zwm#p*YD|o=pc5iI!4+r6gA3c+?9F$S*x^Ce|4Cs*8dic?@Tgw!h#ZDu$Ly64tYH&l7ldEy)MjDj9i#I9bjB-#*^4?Yike^xbu4_5C4fx9a+dK)fX<`;dxa{u`ts5J?upQO)pOAA zis5-M+u3dd4g_`q)Hxb}W`6aZrwJOY`AYl_+^W&lXp8y1cb+lFr=}IB6s9hxHKr9w zN>C_#&#uL6hr4-hCx~zAqF2BEdNkPL`gVDh;>Ho4{ zcsRW6(dhu~hF)WaG}iW98xgls=-qpFR(EUcHrkKrVB^@`zY~yZbWUdH=}) zVRs*KXRHU##3UP_i1Q`j;&bD<$hS+3=tMJ>c#vvT>ut@Nn{?|hgO>B=i@VgS(RWVCv9p~fbAeHBILZ#MQO4DW zS?6KeBhNlb1lG`X{mm{L$24Uh(fmn~jH8pDtA3AH4`gePQ&#P*Af#%S$d@&gZZ+7r z66QC29RADr>(Ad+W{=;I&E9I~(D&~0N}^j4gm2iGLT98%-Jd{jyhzCObw2;{qJJ7) z=NgU?ADn^B(78>jpQ90zE1%&H0zdJ?99Mfv^n7yGb)@2@Yg5sXCuw4$xz@!}T1O_^ zqk03+Hvy3VN2}*44R6dJur~Sr$jlT?{l10JMo(r6O=pV8J85SVP=vdFviRItmbYwq z812QEsuiy)OW6?P+`?f8QRO%2<=gS;IK+IqaSgAH`P5|-8yy1YAs-IPic2H^p$qwJ z{_{=?qJq9@R+1Ai5c2o%F~O_hyb23D9JwFn#ZBF_TJ)smd`R{xhUW4-=h~~J-t?N0 zE-|+cDZomPCn{R4!8*otTToa)SOWRbrKZ*|6+8Y%mTuK{|YK5 XBr1x0{o)0Yh@cP=JG+wl3!?u4Auz&( diff --git a/figures/Fig1-designProcess/express.pdf b/figures/Fig1-designProcess/express.pdf index d28aeaa37c465262e4b24f5c382d715f8a1caa18..1c493fc1e64c60dfa9a57570a1eee3d9eba96656 100644 GIT binary patch delta 8030 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 Js_s3q{{j`RF7yBZ delta 8026 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 VVxGJru`nM@l<59_MJ*+w{{hP11gro6 delta 8071 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 AU;qFB diff --git a/flexibleSubsetSelection/algorithm.py b/flexibleSubsetSelection/algorithm.py index 442096d..008b409 100644 --- a/flexibleSubsetSelection/algorithm.py +++ b/flexibleSubsetSelection/algorithm.py @@ -140,7 +140,7 @@ def worstOfRandom(dataset, lossFunction, subsetSize, minLoss=0, def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, - seed=None): + seed=None, callback=None): """ A greedy algorithm with a greedy swap heuristic for subset selection. @@ -170,6 +170,9 @@ def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, for i in range(maxIterations): log.debug("Iteration %s/%s: Loss %s.", i, maxIterations, loss) + if callback: + callback(iterations, loss) + if i not in indices: zSwapBest = np.copy(z) lossSwapBest = loss @@ -199,7 +202,7 @@ def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, return z, loss # return indicator and final loss def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, - maxIterations=None, seed=None, initialSize=1): + maxIterations=None, seed=None, initialSize=1, callback=None): """ A greedy algorithm for subset selection to minimize the size of the subset such that lossFunction(subset) <= epsilon. @@ -214,6 +217,7 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, seed (int, rng, optional): The random seed or NumPy rng for random generation and reproducibility initialSize (int, optional): Initial size of the subset + callback (function, optional): A callback function for loss values Returns: z (array): Indicator vector of included items in the subset @@ -252,6 +256,8 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, while iterations < maxIterations: log.debug("Iteration: %s, Loss: %s, Error: %s, Subset Size: %s.", iterations, current_loss, error, np.sum(z)) + if callback: + callback(iterations, current_loss, subsetSize=np.sum(z)) # Check if error is less than or equal to epsilon if error <= epsilon: @@ -314,7 +320,7 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, return z, error def greedyMixed(dataset, lossFunction, weight=1.0, minError=0, - maxIterations=None, seed=None, initialSize=1): + maxIterations=None, seed=None, initialSize=1, callback=None): """ A greedy algorithm to minimize the total loss = weight * subsetSize + lossFunction.calculate(). @@ -363,6 +369,8 @@ def greedyMixed(dataset, lossFunction, weight=1.0, minError=0, while iterations < maxIterations: log.debug("Iteration %s: Total Loss %s, Subset Size %s", iterations, total_loss, np.sum(z)) + if callback: + callback(iterations, total_loss, subsetSize=np.sum(z)) # Check if error is less than or equal to minError if error <= minError: diff --git a/flexibleSubsetSelection/plot.py b/flexibleSubsetSelection/plot.py index a545fd4..30eb8e1 100644 --- a/flexibleSubsetSelection/plot.py +++ b/flexibleSubsetSelection/plot.py @@ -4,6 +4,8 @@ from typing import Callable # Third party +from IPython.display import display, clear_output + import matplotlib from matplotlib.axes import Axes from matplotlib.colors import to_rgb, to_hex @@ -346,4 +348,58 @@ def histogram(ax: Axes, color: Color, dataset: (Dataset | None) = None, positions = barPositions[i] + np.arange(numBins) ax.bar(positions, subsetHeights, width=1, - color=color.palette["darkGreen"], alpha=0.5) \ No newline at end of file + color=color.palette["darkGreen"], alpha=0.5) + +class RealTimePlotter: + def __init__(self, color): + # Initialize the figure and axis + self.fig, self.ax = plt.subplots(figsize=(4, 4)) + self.iterations = [] + self.losses = [] + self.subsetSizes = [] + self.color = color + + # Set up the initial plot + self.ax.set_xlabel('Iteration') + self.ax.set_ylabel('Loss') + self.ax.set_title('Real-Time Loss During Solver') + self.ax.set_ylim(bottom=0) # Set the lower y-axis limit to 0 + + # Display the figure initially + display(self.fig) + + def update(self, iteration, loss, subsetSize=None): + # Append the current iteration and loss to lists + self.iterations.append(iteration) + self.losses.append(loss) + self.subsetSizes.append(subsetSize) + + # Clear the previous output (but don't clear the figure) + clear_output(wait=True) + self.ax.clear() + + self.ax.set_xlabel('Iteration') + # self.ax.set_ylabel('Loss') + self.ax.set_title('Minimum Loss') + + # Plot the updated loss values + self.ax.plot(self.iterations, + self.losses, + c=self.color["orange"], + label="Loss", + lw=2) + if subsetSize is not None: + self.ax.plot(self.iterations, + self.subsetSizes, + c=self.color["green"], + label="Subset Size", + lw=2) + self.ax.legend() + + # Display the updated plot + display(self.fig) + plt.close(self.fig) + + def close(self): + # Close the plot when done + plt.close(self.fig) \ No newline at end of file diff --git a/jupyter/Fig1-designProcess.ipynb b/jupyter/Fig1-designProcess.ipynb index 4b11961..6d4bffc 100644 --- a/jupyter/Fig1-designProcess.ipynb +++ b/jupyter/Fig1-designProcess.ipynb @@ -13,17 +13,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - "\n", - "\n", - "\n" + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" ] } ], @@ -33,6 +31,8 @@ "from pathlib import Path\n", "\n", "# Third party\n", + "from IPython.display import clear_output, display\n", + "\n", "import matplotlib.pyplot as plt\n", "import matplotlib_inline\n", "\n", @@ -45,6 +45,7 @@ "# Initialize notebook settings\n", "sns.set_theme() # set seaborn theme\n", "matplotlib_inline.backend_inline.set_matplotlib_formats('svg') # vector plots\n", + "%matplotlib inline\n", "%load_ext autoreload\n", "%autoreload 2" ] @@ -60,23 +61,13 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 114, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "2024-10-10 13:12:15,752 - flexibleSubsetSelection.sets - INFO: Dataset with 200 rows and 2 features: [0, 1] created.\n", - "2024-10-10 13:12:15,753 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/fullData.pickle'.\n" - ] - } - ], + "outputs": [], "source": [ - "directory = \"Fig1-designProcess\" # data directory for this notebook\n", - "seed = 123456789 # random seed for replicability\n", - "fss.logger.setup(level = logging.DEBUG) # set logging level for the package\n", + "directory = \"Fig1-designProcess\" # data directory for this notebook\n", + "seed = 123456789 # random seed for replicability\n", + "fss.logger.setup(level = logging.WARNING) # set logging level for the package\n", "\n", "# Create a random blobs dataset to use as our example dataset\n", "dataset = fss.Dataset(randTypes=\"blobs\", size=(200, 2), seed=seed)\n", @@ -99,146 +90,7 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2024-10-10 13:12:19,144 - flexibleSubsetSelection.sets - INFO: Data preprocessed with function 'hull'.\n", - "2024-10-10 13:12:19,145 - flexibleSubsetSelection.loss - INFO: Initialized a uni-criterion loss function with objective: preserveMetric, solve array: dataArray, selection method: row, and parameters: {'metric': , 'datasetMetric': 48.93447555042436}\n", - "2024-10-10 13:12:19,146 - flexibleSubsetSelection.solver - DEBUG: Initializing Solver with algorithm: greedyMinSubset, lossFunction: Uni-criterion: preserveMetric, hull, savePath: ../data/solverData.csv\n", - "2024-10-10 13:12:19,146 - flexibleSubsetSelection.solver - DEBUG: Log file already exists at ../data/solverData.csv\n", - "2024-10-10 13:12:19,147 - flexibleSubsetSelection.solver - INFO: Initialized a 'greedyMinSubset' solver.\n", - "2024-10-10 13:12:19,147 - flexibleSubsetSelection.algorithm - DEBUG: Solving for a subset such that loss(subset) <= 0.\n", - "2024-10-10 13:12:19,149 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 0, Loss: 42.23945382223514, Error: 42.23945382223514, Subset Size: 3.\n", - "2024-10-10 13:12:19,171 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 1, Loss: 23.054327728930527, Error: 23.054327728930527, Subset Size: 4.\n", - "2024-10-10 13:12:19,191 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 2, Loss: 11.133231203775615, Error: 11.133231203775615, Subset Size: 5.\n", - "2024-10-10 13:12:19,210 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 3, Loss: 1.8340851157977838, Error: 1.8340851157977838, Subset Size: 6.\n", - "2024-10-10 13:12:19,232 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 4, Loss: 0.7160766035798432, Error: 0.7160766035798432, Subset Size: 7.\n", - "2024-10-10 13:12:19,252 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 5, Loss: 0.013246909388804795, Error: 0.013246909388804795, Subset Size: 8.\n", - "2024-10-10 13:12:19,274 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 6, Loss: 1.6379421907686265e-06, Error: 1.6379421907686265e-06, Subset Size: 9.\n", - "2024-10-10 13:12:19,295 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 7, Loss: 0.0, Error: 0.0, Subset Size: 10.\n", - "2024-10-10 13:12:19,296 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 7, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,317 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 8, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,338 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 9, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,361 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 10, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,381 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 11, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,382 - flexibleSubsetSelection.solver - INFO: Selected subset with 'greedyMinSubset' and 'Uni-criterion: preserveMetric, hull' in 0.23s with 0.0 loss.\n", - "2024-10-10 13:12:19,383 - flexibleSubsetSelection.sets - INFO: Created subset of size 7x2 in 0.23s with 0.0 loss.\n", - "2024-10-10 13:12:19,384 - flexibleSubsetSelection.solver - INFO: Saved solver performance data to ../data/solverData.csv.\n", - "2024-10-10 13:12:19,385 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/hullSubset.pickle'.\n" - ] - } - ], - "source": [ - "# Precalculate the hull metric on the full dataset\n", - "dataset.preprocess(hull = fss.metric.hull)\n", - "\n", - "# Create a unicriterion loss function with the hull metric and precomputation\n", - "lossFunction = fss.UniCriterion(objective = fss.objective.preserveMetric, \n", - " metric = fss.metric.hull,\n", - " datasetMetric = dataset.hull)\n", - "\n", - "# Create a solve method with a greedy algorithm and a set subset size\n", - "solver = fss.Solver(algorithm = fss.algorithm.greedyMinSubset, \n", - " lossFunction = lossFunction)\n", - "\n", - "# Solve for a convex hull subset\n", - "subsetHull = solver.solve(dataset, epsilon=0, initialSize=3)\n", - "subsetHull.save(f\"{directory}/hullSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Outliers Objective\n", - "\n", - "Applying this objective allows us to select a subset of 40 points with the highest local outlier effect.\n", - "\n", - "\\begin{align*}\n", - "\\max_{S \\in \\mathbb{S}} & \\quad \\text{LOF}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 40\n", - "\\end{align*}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2024-10-10 13:10:40,381 - flexibleSubsetSelection.sets - INFO: Data preprocessed with function 'outlierness'.\n", - "2024-10-10 13:10:40,381 - flexibleSubsetSelection.loss - INFO: Initialized a uni-criterion loss function with objective: sum, solve array: outlierness, selection method: row, and parameters: {}\n", - "2024-10-10 13:10:40,417 - flexibleSubsetSelection.solver - INFO: Selected subset with 'greedySwap' and 'Uni-criterion: sum, outlierness' in 0.04s with -66.43006587269934 loss.\n", - "2024-10-10 13:10:40,418 - flexibleSubsetSelection.sets - INFO: Created subset of size 40x2 in 0.04s with -66.43 loss.\n", - "2024-10-10 13:10:40,419 - flexibleSubsetSelection.solver - INFO: Saved solver performance data to ../data/solverData.csv.\n", - "2024-10-10 13:10:40,421 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/outliersSubset.pickle'.\n" - ] - } - ], - "source": [ - "# Precalculate the outlierness (local outlier effect) of the full dataset\n", - "dataset.preprocess(outlierness = fss.objective.outlierness)\n", - "\n", - "# Create a loss function that is just the sum of the LOF in the subset\n", - "solver.lossFunction = fss.UniCriterion(objective = np.sum, \n", - " solveArray = \"outlierness\")\n", - "solver.algorithm = fss.algorithm.greedySwap\n", - "\n", - "# Solve for an outlier subset\n", - "subsetOutliers = solver.solve(dataset, subsetSize=40, maxIterations=100)\n", - "subsetOutliers.save(f\"{directory}/outliersSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Distinctness Objective\n", - "\n", - "Applying this objective allows us to select a subset of 60 points that are distant from their nearest neighbors in 2D space.\n", - "\n", - "\\begin{align*}\n", - "\\max_{S \\in \\mathbb{S}} & \\quad \\text{Distinctness}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 60\n", - "\\end{align*}" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a unicriterion loss function with the distinctness objective\n", - "dataset.preprocess(distances = fss.metric.distanceMatrix)\n", - "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", - " solveArray = \"distances\",\n", - " selectBy = \"matrix\")\n", - "\n", - "# Solve for distinctness subset\n", - "subsetDistinct = solver.solve(dataset=dataset, subsetSize=60)\n", - "subsetDistinct.save(f\"{directory}/distinctSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot\n", - "\n", - "Now we visualize these three example objectives by plotting the dataset and subsets in 3 scatterplots." - ] - }, - { - "cell_type": "code", - "execution_count": 10, + "execution_count": 115, "metadata": {}, "outputs": [ { @@ -247,12 +99,12 @@ "\n", "\n", - "\n", + "\n", " \n", " \n", " \n", " \n", - " 2024-10-10T12:40:59.708896\n", + " 2024-10-11T15:31:57.532307\n", " image/svg+xml\n", " \n", " \n", @@ -267,604 +119,236 @@ " \n", " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "\" transform=\"scale(0.015625)\"/>\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", "\n" ], "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -1523,118 +970,49 @@ } ], "source": [ - "# Initialize color and plot settings\n", - "color = fss.Color()\n", - "fss.plot.initialize(color, font=\"DejaVu Sans\")\n", + "# Precalculate the hull metric on the full dataset\n", + "dataset.preprocess(hull = fss.metric.hull)\n", "\n", - "# Plot the three different resulting subsets as scatterplots\n", - "titleSize = 24\n", - "subtitleSize = 18\n", - "titles = [\"Hull\", \"Outliers\", \"Distinctness\"]\n", - "subsets = [subsetHull, subsetOutliers, subsetDistinct]\n", + "# Create a unicriterion loss function with the hull metric and precomputation\n", + "lossFunction = fss.UniCriterion(objective = fss.objective.preserveMetric, \n", + " metric = fss.metric.hull,\n", + " datasetMetric = dataset.hull)\n", "\n", - "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", - "fig.text(0.49, 1, '1. Express', ha='center', va='center', fontsize=titleSize)\n", + "# Create a solve method with a greedy algorithm and a set subset size\n", + "solver = fss.Solver(algorithm = fss.algorithm.greedyMinSubset, \n", + " lossFunction = lossFunction)\n", "\n", - "for i, ax in enumerate(fig.axes):\n", - " ax.grid(visible=False)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " ax.set_title(titles[i], fontsize=subtitleSize)\n", - " # ax.set_aspect(\"equal\")\n", + "# Initialize color and plot settings\n", + "color = fss.Color()\n", + "fss.plot.initialize(color, font=\"DejaVu Sans\")\n", + "lossPlotter = fss.plot.RealTimePlotter(color)\n", "\n", - " fss.plot.scatter(ax = ax, \n", - " color = color, \n", - " dataset = dataset, \n", - " subset = subsets[i], \n", - " alpha = 0.6)\n", + "# Solve for a convex hull subset\n", + "subsetHull = solver.solve(dataset, \n", + " epsilon = 0, \n", + " initialSize = 3, \n", + " callback = lossPlotter.update)\n", "\n", - "plt.savefig(f\"../figures/{directory}/express.pdf\", bbox_inches=\"tight\")" + "subsetHull.save(f\"{directory}/hullSubset\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Blend\n", + "### Outliers Objective\n", "\n", - "For visualizations with multiple criteria, objectives can be combined together to achieve more complicated outcomes. Multiple criteria can be balanced using the weight parameters to ensure the objectives apply to the subsets at desirable levels. Here we create three different subsets that blend a distribution objective (using the earth movers distance as the metric) with the distinctness objective from the previous section. Each subset blends the two objectives differently by varying the weights.\n", + "Applying this objective allows us to select a subset of 40 points with the highest local outlier effect.\n", "\n", "\\begin{align*}\n", - "\\min_{S \\in \\mathbb{S}} & \\quad \\lambda_0 \\text{EMD}(S) + \\lambda_1 \\text{Distinctness}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 80\n", + "\\max_{S \\in \\mathbb{S}} & \\quad \\text{LOF}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 40\n", "\\end{align*}" ] }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "subsetSize = 80 # The size of subsets being selected with blended objectives\n", - "\n", - "# Use distribution and distinctness objectives\n", - "objectives = [fss.objective.earthMoversDistance, fss.objective.distinctness]\n", - "\n", - "# Parameters of the distribution and distinctness objectives\n", - "parameters = [{\"dataset\": dataset.dataArray}, \n", - " {\"solveArray\": \"distances\", \"selectBy\": \"matrix\"}]\n", - "\n", - "# Create the multicriterion loss function from the objectives and weight them\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[100, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend1 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend1.save(f\"{directory}/blend1Subset\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Update the weights to provide less emphasis on the distribution objective\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[10, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend2 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend2.save(f\"{directory}/blend2Subset\")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Update the weights to an even weight of the two objectives\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[1, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend3 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend3.save(f\"{directory}/blend3Subset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot\n", - "\n", - "Now we visualize these three example blended subsets by plotting the dataset and subsets in 3 scatterplots." - ] - }, - { - "cell_type": "code", - "execution_count": 14, + "execution_count": 117, "metadata": {}, "outputs": [ { @@ -1643,12 +1021,12 @@ "\n", "\n", - "\n", + "\n", " \n", " \n", " \n", " \n", - " 2024-10-10T12:41:49.800928\n", + " 2024-10-11T15:35:55.117881\n", " image/svg+xml\n", " \n", " \n", @@ -1663,320 +1041,219 @@ " \n", " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "M 2034 4750 \n", + "Q 2819 4750 3233 4129 \n", + "Q 3647 3509 3647 2328 \n", + "Q 3647 1150 3233 529 \n", + "Q 2819 -91 2034 -91 \n", + "Q 1250 -91 836 529 \n", + "Q 422 1150 422 2328 \n", + "Q 422 3509 836 4129 \n", + "Q 1250 4750 2034 4750 \n", + "z\n", + "\" transform=\"scale(0.015625)\"/>\n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "\" style=\"fill: #eff0f2; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter\"/>\n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Precalculate the outlierness (local outlier effect) of the full dataset\n", + "dataset.preprocess(outlierness = fss.objective.outlierness)\n", + "\n", + "# Create a loss function that is just the sum of the LOF in the subset\n", + "solver.lossFunction = fss.UniCriterion(objective = np.sum, \n", + " solveArray = \"outlierness\")\n", + "solver.algorithm = fss.algorithm.greedySwap\n", + "\n", + "# Solve for an outlier subset\n", + "subsetOutliers = solver.solve(dataset, \n", + " subsetSize = 40, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "\n", + "subsetOutliers.save(f\"{directory}/outliersSubset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Distinctness Objective\n", + "\n", + "Applying this objective allows us to select a subset of 60 points that are distant from their nearest neighbors in 2D space.\n", + "\n", + "\\begin{align*}\n", + "\\max_{S \\in \\mathbb{S}} & \\quad \\text{Distinctness}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 60\n", + "\\end{align*}" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:37:26.487257\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a unicriterion loss function with the distinctness objective\n", + "dataset.preprocess(distances = fss.metric.distanceMatrix)\n", + "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", + " solveArray = \"distances\",\n", + " selectBy = \"matrix\")\n", + "\n", + "# Solve for distinctness subset\n", + "subsetDistinct = solver.solve(dataset=dataset, \n", + " subsetSize=60, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct.save(f\"{directory}/distinctSubset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot\n", + "\n", + "Now we visualize these three example objectives by plotting the dataset and subsets in 3 scatterplots." + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:37:50.365496\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the three different resulting subsets as scatterplots\n", + "titleSize = 24\n", + "subtitleSize = 18\n", + "titles = [\"Hull\", \"Outliers\", \"Distinctness\"]\n", + "subsets = [subsetHull, subsetOutliers, subsetDistinct]\n", + "\n", + "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", + "fig.text(0.49, 1, '1. Express', ha='center', va='center', fontsize=titleSize)\n", + "\n", + "for i, ax in enumerate(fig.axes):\n", + " ax.grid(visible=False)\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_title(titles[i], fontsize=subtitleSize)\n", + " # ax.set_aspect(\"equal\")\n", + "\n", + " fss.plot.scatter(ax = ax, \n", + " color = color, \n", + " dataset = dataset, \n", + " subset = subsets[i], \n", + " alpha = 0.6)\n", + "\n", + "plt.savefig(f\"../figures/{directory}/express.pdf\", bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Blend\n", + "\n", + "For visualizations with multiple criteria, objectives can be combined together to achieve more complicated outcomes. Multiple criteria can be balanced using the weight parameters to ensure the objectives apply to the subsets at desirable levels. Here we create three different subsets that blend a distribution objective (using the earth movers distance as the metric) with the distinctness objective from the previous section. Each subset blends the two objectives differently by varying the weights.\n", + "\n", + "\\begin{align*}\n", + "\\min_{S \\in \\mathbb{S}} & \\quad \\lambda_0 \\text{EMD}(S) + \\lambda_1 \\text{Distinctness}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 80\n", + "\\end{align*}" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:39:35.141220\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "subsetSize = 80 # The size of subsets being selected with blended objectives\n", + "\n", + "# Use distribution and distinctness objectives\n", + "objectives = [fss.objective.earthMoversDistance, fss.objective.distinctness]\n", + "\n", + "# Parameters of the distribution and distinctness objectives\n", + "parameters = [{\"dataset\": dataset.dataArray}, \n", + " {\"solveArray\": \"distances\", \"selectBy\": \"matrix\"}]\n", + "\n", + "# Create the multicriterion loss function from the objectives and weight them\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[100, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend1 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend1.save(f\"{directory}/blend1Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:41:07.736944\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Update the weights to provide less emphasis on the distribution objective\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[10, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend2 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend2.save(f\"{directory}/blend2Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:42:16.644960\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Update the weights to an even weight of the two objectives\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[1, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend3 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend3.save(f\"{directory}/blend3Subset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot\n", + "\n", + "Now we visualize these three example blended subsets by plotting the dataset and subsets in 3 scatterplots." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-10T13:23:57.066961\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the three subsets with different blends of the two objectives\n", + "titles = [\"More Distribution,\\nLess Distinct\", \"\", \n", + " \"Less Distribution,\\nMore Distinct\"]\n", + "subsets = [subsetBlend1, subsetBlend2, subsetBlend3]\n", + "\n", + "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", + "fig.text(0.49, 1, '2. Blend', ha='center', va='center', fontsize=titleSize)\n", + "\n", + "for i, ax in enumerate(fig.axes):\n", + " ax.grid(visible=False)\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_title(titles[i], fontsize=subtitleSize)\n", + "\n", + " fss.plot.scatter(ax = ax, \n", + " color = color,\n", + " dataset = dataset,\n", + " subset = subsets[i],\n", + " alpha = 0.6)\n", + "\n", + "plt.savefig(f\"../figures/{directory}/blend.pdf\", bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tune\n", + "\n", + "Along with the weight parameters that help in blending objectives, the parameters of the objectives and the optimization formulation can be tuned to select a subset that is more effective for a given visualization. For example, the subset size, loss bounds, and subset weight parameters can be used to tune the subset size for a particular visualization. Objectives may have parameters associated with them such as the number of clusters in a clustering objective, the amount of seperation in a distinctness objective, or the smoothing parameter of a kernel density estimation. These provide additional flexibility to tune the objectives to a desirable level. Here we tune the subset size by varying the weight given to this fundamental characteristic of a subset to three different levels. \n", + "\n", + "$$\\min_{S \\in \\mathbb{S}} \\space \\lambda \\|S\\| + \\text{Distinctness}(S)$$" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:46:53.637614\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a unicriterion loss function with the distinctness objective\n", + "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", + " solveArray = \"distances\",\n", + " selectBy = \"matrix\")\n", + "solver.algorithm = fss.algorithm.greedyMixed\n", + "\n", + "# Solve for subsets with 3 different subset sizes\n", + "subsetDistinct1 = solver.solve(dataset=dataset, weight=0.5, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct1.save(f\"{directory}/distinct1Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:47:08.133220\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "subsetDistinct2 = solver.solve(dataset=dataset, weight=0.25, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct2.save(f\"{directory}/distinct2Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:47:24.868033\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", "\n" ], "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -3142,60 +11274,9 @@ } ], "source": [ - "# Plot the three subsets with different blends of the two objectives\n", - "titles = [\"More Distribution,\\nLess Distinct\", \"\", \n", - " \"Less Distribution,\\nMore Distinct\"]\n", - "subsets = [subsetBlend1, subsetBlend2, subsetBlend3]\n", - "\n", - "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", - "fig.text(0.49, 1, '2. Blend', ha='center', va='center', fontsize=titleSize)\n", - "\n", - "for i, ax in enumerate(fig.axes):\n", - " ax.grid(visible=False)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " ax.set_title(titles[i], fontsize=subtitleSize)\n", - "\n", - " fss.plot.scatter(ax = ax, \n", - " color = color,\n", - " dataset = dataset,\n", - " subset = subsets[i],\n", - " alpha = 0.6)\n", - "\n", - "plt.savefig(f\"../figures/{directory}/blend.pdf\", bbox_inches=\"tight\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tune\n", - "\n", - "Along with the weight parameters that help in blending objectives, the parameters of the objectives and the optimization formulation can be tuned to select a subset that is more effective for a given visualization. For example, the subset size, loss bounds, and subset weight parameters can be used to tune the subset size for a particular visualization. Objectives may have parameters associated with them such as the number of clusters in a clustering objective, the amount of seperation in a distinctness objective, or the smoothing parameter of a kernel density estimation. These provide additional flexibility to tune the objectives to a desirable level. Here we tune the subset size by varying the weight given to this fundamental characteristic of a subset to three different levels. \n", - "\n", - "$$\\min_{S \\in \\mathbb{S}} \\space \\lambda \\|S\\| + \\text{Distinctness}(S)$$" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a unicriterion loss function with the distinctness objective\n", - "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", - " solveArray = \"distances\",\n", - " selectBy = \"matrix\")\n", - "solver.algorithm = fss.algorithm.greedyMixed\n", "\n", - "# Solve for subsets with 3 different subset sizes\n", - "subsetDistinct1 = solver.solve(dataset=dataset, weight=0.5, initialSize=3)\n", - "subsetDistinct1.save(f\"{directory}/distinct1Subset\")\n", - "\n", - "subsetDistinct2 = solver.solve(dataset=dataset, weight=0.25, initialSize=3)\n", - "subsetDistinct2.save(f\"{directory}/distinct2Subset\")\n", - "\n", - "subsetDistinct3 = solver.solve(dataset=dataset, weight=0.05, initialSize=3)\n", + "subsetDistinct3 = solver.solve(dataset=dataset, weight=0.05, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", "subsetDistinct3.save(f\"{directory}/distinct3Subset\")" ] }, @@ -3210,7 +11291,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -3224,7 +11305,7 @@ " \n", " \n", " \n", - " 2024-10-10T12:41:50.823898\n", + " 2024-10-10T13:23:58.321458\n", " image/svg+xml\n", " \n", " \n", @@ -3279,7 +11360,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -3797,7 +11878,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -3865,245 +11947,229 @@ "\" style=\"fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4139,207 +12205,207 @@ "\" style=\"fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4387,51 +12453,99 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4523,13 +12637,13 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n",