├── .gitignore ├── LICENSE ├── NOTES.md ├── README.md ├── data ├── adult_processed.csv ├── bankruptcy_processed.csv ├── breastcancer_processed.csv ├── haberman_processed.csv ├── heart_processed.csv ├── mammo_processed.csv ├── mushroom_processed.csv └── spambase_processed.csv ├── demos └── ex_1_basic_functionality.py ├── docs └── usrcplex.pdf ├── images └── slim_mushroom.png ├── requirements.txt ├── setup.py └── slim_python ├── SLIMCoefficientConstraints.py ├── __init__.py ├── create_slim_IP.py ├── helper_functions.py └── tests └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Git Ignore File 2 | # This file tells git what kind of files to ignore in commits 3 | 4 | # JetBrains IDE Stuff 5 | # https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 6 | 7 | # User-specific stuff: 8 | .idea/* 9 | .idea/workspace.xml 10 | .idea/tasks.xml 11 | .idea/dictionaries 12 | .idea/vcs.xml 13 | .idea/jsLibraryMappings.xml 14 | 15 | # Sensitive or high-churn files: 16 | .idea/dataSources.ids 17 | .idea/dataSources.xml 18 | .idea/dataSources.local.xml 19 | .idea/sqlDataSources.xml 20 | .idea/dynamic.xml 21 | .idea/uiDesigner.xml 22 | 23 | # Logs and Run-Based Variables 24 | .log 25 | .setting 26 | 27 | # R Stuff 28 | .Rhistory 29 | .Rapp.history 30 | .RData 31 | .Rproj.user/ 32 | 33 | # OSX File Types 34 | .dropbox 35 | .DS_Store 36 | .DS_Store? 37 | ._* 38 | .Spotlight-V100 39 | .Trashes 40 | ehthumbs.db 41 | Thumbs.db 42 | Icon 43 | 44 | # General Filetypes 45 | *.7z 46 | *.dmg 47 | *.gz 48 | *.iso 49 | *.jar 50 | *.rar 51 | *.tar 52 | *.zip 53 | *.tar.gz 54 | 55 | # Compiled Source 56 | *.com 57 | *.class 58 | *.dll 59 | *.exe 60 | *.o 61 | *.so -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | #TODO 2 | 3 | - support to add mip_starts 4 | - support for only binary datasets 5 | - support for class weights 6 | - support for case weights 7 | - parameter selection helper 8 | 9 | #REFERENCES 10 | http://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/ 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``slim-python`` is a package to learn customized *scoring systems* for decision-making problems. 2 | 3 | These are simple decision aids that let users make yes-no predictions by adding and subtracting a few small numbers. ![SLIM scoring system for the mushrooms dataset](https://github.com/ustunb/slim-python/blob/master/images/slim_mushroom.png) 4 | 5 | SLIM is designed to learn the most accurate scoring system for a given dataset and set of constraints. These models are produced by solving a hard optimization problem that directly optimizes for accuracy, sparsity, and customized constraints (e.g., hard limits on model size, TPR, FPR). 6 | 7 | ## Requirements 8 | 9 | ``slim-python`` was developed using Python 2.7.11 and CPLEX 12.6.2. 10 | 11 | ### CPLEX 12 | 13 | *CPLEX* is cross-platform commercial optimization tool with a Pytho API. It is freely available to students and faculty members at accredited institutions as part of the IBM Academic Initiative. To get CPLEX: 14 | 15 | 1. Join the [IBM Academic Initiative](http://www-304.ibm.com/ibm/university/academic/pub/page/mem_join). Note that it may take up to a week to obtain approval. 16 | 2. Download *IBM ILOG CPLEX Optimization Studio V12.6.1* (or higher) from the [software catalog](https://www-304.ibm.com/ibm/university/academic/member/softwaredownload) 17 | 3. Install the file on your computer. Note mac/unix users will [need to install a .bin file](http://www-01.ibm.com/support/docview.wss?uid=swg21444285). 18 | 4. Setup the CPLEX Python modules [as described here here](http://www.ibm.com/support/knowledgecenter/SSSA5P_12.6.3/ilog.odms.cplex.help/CPLEX/GettingStarted/topics/set_up/Python_setup.html). 19 | 20 | 21 | Please check the [CPLEX user manual](http://www-01.ibm.com/support/knowledgecenter/SSSA5P/welcome) or the [CPLEX forums](https://www.ibm.com/developerworks/community/forums/html/forum?id=11111111-0000-0000-0000-000000002059) if you have problems installing CPLEX. 22 | 23 | ## Citation 24 | 25 | If you use SLIM for academic research, please cite [our paper](http://http//arxiv.org/abs/1502.04269/)! 26 | 27 | ``` 28 | @article{ 29 | ustun2015slim, 30 | year = {2015}, 31 | issn = {0885-6125}, 32 | journal = {Machine Learning}, 33 | doi = {10.1007/s10994-015-5528-6}, 34 | title = {Supersparse linear integer models for optimized medical scoring systems}, 35 | url = {http://dx.doi.org/10.1007/s10994-015-5528-6}, 36 | publisher = { Springer US}, 37 | author = {Ustun, Berk and Rudin, Cynthia}, 38 | pages = {1-43}, 39 | language = {English} 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /data/bankruptcy_processed.csv: -------------------------------------------------------------------------------- 1 | "NotBankrupt","IndustrialRisk","ManagementRisk","FinancialFlexibilityRisk","CredibilityRisk","CompetitiveRisk","OperatingRisk" 1,1,1,0,0,0,1 1,-1,-1,0,0,0,-1 1,0,0,0,0,0,0 1,1,1,1,1,1,1 1,-1,-1,1,1,1,-1 1,0,0,1,1,1,0 1,1,1,0,1,1,1 1,1,1,1,0,0,1 1,1,1,0,1,0,1 1,1,1,0,0,1,1 1,1,1,1,1,0,1 1,1,1,1,0,1,1 1,-1,-1,0,1,1,-1 1,-1,-1,1,0,0,-1 1,-1,-1,0,1,0,-1 1,-1,-1,0,1,0,-1 1,-1,-1,0,0,1,-1 1,-1,-1,1,1,0,-1 1,-1,-1,1,0,1,-1 1,0,0,0,1,1,0 1,0,0,1,0,0,0 1,0,0,0,1,0,0 1,0,0,0,0,1,0 1,0,0,1,1,0,0 1,0,0,1,0,1,0 1,1,-1,0,0,0,1 1,-1,1,0,0,0,-1 1,1,-1,0,0,0,-1 1,1,-1,1,1,1,1 1,-1,1,1,1,1,-1 1,1,-1,1,1,1,-1 1,-1,-1,0,1,1,1 1,1,-1,1,0,0,1 1,-1,1,0,1,0,1 1,-1,1,0,0,1,-1 1,1,-1,1,1,0,-1 1,-1,1,1,0,1,0 1,0,-1,0,1,1,0 1,0,1,1,0,0,0 1,0,0,0,1,0,1 1,0,0,0,0,1,-1 1,-1,0,1,1,1,-1 1,0,-1,1,0,1,-1 1,0,1,1,0,1,-1 1,-1,-1,1,0,1,1 1,-1,-1,1,1,1,1 1,1,0,1,1,1,-1 1,0,1,1,1,1,-1 1,0,-1,-1,0,1,1 1,0,1,1,0,1,1 1,1,0,1,0,1,-1 1,0,-1,0,0,1,1 1,0,-1,0,0,1,-1 1,0,-1,0,0,1,0 1,0,0,-1,1,1,0 1,0,0,-1,1,1,1 1,0,1,1,1,1,1 1,0,1,0,0,0,1 1,-1,1,-1,1,1,0 1,-1,-1,1,1,1,0 1,0,0,0,1,1,0 1,0,0,0,1,1,1 1,1,0,0,1,1,1 1,0,-1,-1,1,1,0 1,1,-1,-1,1,1,0 1,0,0,-1,1,1,1 1,1,0,1,-1,1,-1 1,1,0,-1,0,1,-1 1,1,1,1,0,1,-1 1,1,0,1,-1,1,-1 1,1,0,0,1,1,-1 1,1,1,0,1,1,1 1,1,0,1,0,1,1 1,1,1,0,0,1,-1 1,0,0,0,0,0,1 1,1,1,0,1,1,-1 1,0,1,-1,1,0,1 1,0,1,0,1,0,1 1,1,0,-1,0,1,0 1,0,1,-1,1,0,1 1,1,0,0,0,1,0 1,0,1,0,1,0,1 1,0,1,1,1,1,1 1,1,0,0,-1,1,1 1,0,1,0,0,0,1 1,0,-1,-1,-1,1,1 1,-1,1,-1,1,1,0 1,1,-1,0,-1,0,1 1,-1,-1,1,1,1,0 1,0,0,0,1,1,0 1,0,0,0,1,1,1 1,1,0,0,1,1,1 1,0,-1,-1,1,1,0 1,0,0,-1,1,1,1 1,1,0,1,-1,1,-1 1,1,1,1,0,1,-1 1,1,0,1,-1,1,-1 1,1,0,0,1,1,-1 1,1,1,0,1,1,1 1,1,0,1,0,1,1 1,1,1,0,0,1,-1 1,0,0,0,0,0,1 1,1,1,0,1,1,-1 1,0,1,-1,1,0,1 1,1,0,0,0,1,0 1,0,1,0,1,0,1 1,0,1,-1,1,0,1 1,0,1,0,1,0,1 1,1,1,0,0,0,1 1,-1,-1,0,0,0,-1 1,0,0,0,0,0,0 1,1,1,1,1,1,1 1,-1,-1,1,1,1,-1 1,0,0,1,1,1,0 1,1,1,0,1,1,1 1,1,1,1,0,0,1 1,1,1,0,1,0,1 1,1,1,0,0,1,1 1,1,1,1,1,0,1 1,1,1,1,0,1,1 1,-1,-1,0,1,1,-1 1,-1,-1,1,0,0,-1 1,-1,-1,0,1,0,-1 1,-1,-1,0,1,0,-1 1,-1,-1,0,0,1,-1 1,-1,-1,1,1,0,-1 1,-1,-1,1,0,1,-1 1,0,0,0,1,1,0 1,0,0,1,0,0,0 1,0,0,0,1,0,0 1,0,0,0,0,1,0 1,0,0,1,1,0,0 1,0,0,1,0,1,0 1,1,-1,0,0,0,1 1,-1,1,0,0,0,-1 1,1,-1,0,0,0,-1 1,1,-1,1,1,1,1 1,-1,1,1,1,1,-1 1,1,-1,1,1,1,-1 1,-1,-1,0,1,1,1 1,1,-1,1,0,0,1 1,-1,1,0,1,0,1 1,-1,1,0,0,1,-1 0,0,-1,-1,-1,-1,0 0,1,-1,-1,-1,-1,-1 0,-1,1,-1,-1,-1,-1 0,0,1,-1,0,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,-1,-1,0,-1,0 0,-1,-1,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,-1,-1,-1,0,-1,1 0,-1,-1,-1,0,-1,-1 0,-1,-1,0,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,1,-1,-1,-1,0,0 0,0,-1,-1,-1,-1,0 0,0,-1,-1,-1,-1,0 0,0,0,-1,-1,-1,1 0,0,-1,-1,-1,-1,-1 0,1,0,-1,-1,-1,0 0,1,-1,-1,-1,-1,1 0,1,0,-1,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,0,0,-1,-1,-1,-1 0,0,0,-1,-1,-1,-1 0,1,1,-1,-1,-1,-1 0,0,1,-1,-1,-1,-1 0,1,0,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,-1,1,-1,-1,-1,-1 0,0,1,-1,0,-1,-1 0,-1,-1,-1,1,-1,1 0,-1,-1,-1,-1,-1,-1 0,-1,-1,-1,0,-1,0 0,-1,-1,-1,1,-1,-1 0,-1,-1,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,-1,-1,-1,0,-1,1 0,-1,-1,-1,0,-1,-1 0,-1,-1,0,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,1,-1,-1,-1,0,0 0,1,-1,-1,-1,0,0 0,0,-1,-1,-1,-1,0 0,-1,-1,-1,-1,-1,0 0,-1,1,-1,-1,-1,-1 0,0,1,-1,0,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,-1,-1,0,-1,0 0,-1,-1,-1,1,-1,-1 0,-1,-1,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,-1,-1,-1,0,-1,1 0,1,-1,-1,-1,-1,1 0,1,0,-1,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,0,0,-1,-1,-1,-1 0,0,0,-1,-1,-1,-1 0,-1,-1,-1,0,-1,-1 0,-1,-1,0,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,0,1,0,-1,1 0,1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,0,0,-1,-1,-1,-1 0,0,0,-1,-1,-1,1 0,0,-1,-1,-1,-1,-1 0,1,0,-1,-1,-1,0 0,1,-1,-1,-1,-1,1 0,1,0,-1,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,0,0,-1,-1,-1,-1 0,0,0,-1,-1,-1,-1 0,0,1,-1,-1,-1,-1 0,1,0,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,0,-1,-1,-1,-1 0,0,-1,-1,-1,-1,0 0,1,-1,-1,-1,-1,-1 0,-1,1,-1,-1,-1,-1 0,0,1,-1,0,-1,-1 0,-1,-1,-1,-1,-1,-1 0,-1,-1,-1,0,-1,0 0,-1,-1,-1,-1,-1,1 0,-1,-1,-1,-1,-1,0 0,-1,-1,-1,0,-1,1 0,-1,-1,-1,0,-1,-1 0,-1,-1,0,-1,-1,-1 0,1,-1,-1,-1,-1,-1 0,0,-1,-1,-1,-1,-1 0,-1,-1,-1,-1,-1,-1 0,1,-1,-1,-1,0,0 -------------------------------------------------------------------------------- /data/breastcancer_processed.csv: -------------------------------------------------------------------------------- 1 | "Benign","ClumpThickness","UniformityOfCellSize","UniformityOfCellShape","MarginalAdhesion","SingleEpithelialCellSize","BareNuclei","BlandChromatin","NormalNucleoli","Mitoses" 0,5,1,1,1,2,1,3,1,1 0,5,4,4,5,7,10,3,2,1 0,3,1,1,1,2,2,3,1,1 0,6,8,8,1,3,4,3,7,1 0,4,1,1,3,2,1,3,1,1 1,8,10,10,8,7,10,9,7,1 0,1,1,1,1,2,10,3,1,1 0,2,1,2,1,2,1,3,1,1 0,2,1,1,1,2,1,1,1,5 0,4,2,1,1,2,1,2,1,1 0,1,1,1,1,1,1,3,1,1 0,2,1,1,1,2,1,2,1,1 1,5,3,3,3,2,3,4,4,1 0,1,1,1,1,2,3,3,1,1 1,8,7,5,10,7,9,5,5,4 1,7,4,6,4,6,1,4,3,1 0,4,1,1,1,2,1,2,1,1 0,4,1,1,1,2,1,3,1,1 1,10,7,7,6,4,10,4,1,2 0,6,1,1,1,2,1,3,1,1 1,7,3,2,10,5,10,5,4,4 1,10,5,5,3,6,7,7,10,1 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 1,5,2,3,4,2,7,3,6,1 0,3,2,1,1,1,1,2,1,1 0,5,1,1,1,2,1,2,1,1 0,2,1,1,1,2,1,2,1,1 0,1,1,3,1,2,1,1,1,1 0,3,1,1,1,1,1,2,1,1 0,2,1,1,1,2,1,3,1,1 1,10,7,7,3,8,5,7,4,3 0,2,1,1,2,2,1,3,1,1 0,3,1,2,1,2,1,2,1,1 0,2,1,1,1,2,1,2,1,1 1,10,10,10,8,6,1,8,9,1 0,6,2,1,1,1,1,7,1,1 1,5,4,4,9,2,10,5,6,1 1,2,5,3,3,6,7,7,5,1 1,10,4,3,1,3,3,6,5,2 1,6,10,10,2,8,10,7,3,3 1,5,6,5,6,10,1,3,1,1 1,10,10,10,4,8,1,8,10,1 0,1,1,1,1,2,1,2,1,2 1,3,7,7,4,4,9,4,8,1 0,1,1,1,1,2,1,2,1,1 0,4,1,1,3,2,1,3,1,1 1,7,8,7,2,4,8,3,8,2 1,9,5,8,1,2,3,2,1,5 1,5,3,3,4,2,4,3,4,1 1,10,3,6,2,3,5,4,10,2 1,5,5,5,8,10,8,7,3,7 1,10,5,5,6,8,8,7,1,1 1,10,6,6,3,4,5,3,6,1 1,8,10,10,1,3,6,3,9,1 1,8,2,4,1,5,1,5,4,4 1,5,2,3,1,6,10,5,1,1 1,9,5,5,2,2,2,5,1,1 1,5,3,5,5,3,3,4,10,1 0,1,1,1,1,2,2,2,1,1 1,9,10,10,1,10,8,3,3,1 1,6,3,4,1,5,2,3,9,1 0,1,1,1,1,2,1,2,1,1 1,10,4,2,1,3,2,4,3,10 0,4,1,1,1,2,1,3,1,1 1,5,3,4,1,8,10,4,9,1 1,8,3,8,3,4,9,8,9,8 0,1,1,1,1,2,1,3,2,1 0,5,1,3,1,2,1,2,1,1 1,6,10,2,8,10,2,7,8,10 0,1,3,3,2,2,1,7,2,1 1,9,4,5,10,6,10,4,8,1 1,10,6,4,1,3,4,3,2,3 0,1,1,2,1,2,2,4,2,1 0,1,1,4,1,2,1,2,1,1 0,5,3,1,2,2,1,2,1,1 0,3,1,1,1,2,3,3,1,1 0,2,1,1,1,3,1,2,1,1 0,2,2,2,1,1,1,7,1,1 0,4,1,1,2,2,1,2,1,1 0,5,2,1,1,2,1,3,1,1 0,3,1,1,1,2,2,7,1,1 1,3,5,7,8,8,9,7,10,7 1,5,10,6,1,10,4,4,10,10 1,3,3,6,4,5,8,4,4,1 1,3,6,6,6,5,10,6,8,3 0,4,1,1,1,2,1,3,1,1 0,2,1,1,2,3,1,2,1,1 0,1,1,1,1,2,1,3,1,1 0,3,1,1,2,2,1,1,1,1 0,4,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,2,1,1 0,2,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,3,1,1 0,2,1,1,2,2,1,1,1,1 0,5,1,1,1,2,1,3,1,1 1,9,6,9,2,10,6,2,9,10 1,7,5,6,10,5,10,7,9,4 1,10,3,5,1,10,5,3,10,2 1,2,3,4,4,2,5,2,5,1 0,4,1,2,1,2,1,3,1,1 1,8,2,3,1,6,3,7,1,1 1,10,10,10,10,10,1,8,8,8 1,7,3,4,4,3,3,3,2,7 1,10,10,10,8,2,10,4,1,1 1,1,6,8,10,8,10,5,7,1 0,1,1,1,1,2,1,2,3,1 1,6,5,4,4,3,9,7,8,3 0,1,3,1,2,2,2,5,3,2 1,8,6,4,3,5,9,3,1,1 1,10,3,3,10,2,10,7,3,3 1,10,10,10,3,10,8,8,1,1 0,3,3,2,1,2,3,3,1,1 0,1,1,1,1,2,5,1,1,1 0,8,3,3,1,2,2,3,2,1 1,4,5,5,10,4,10,7,5,8 0,1,1,1,1,4,3,1,1,1 0,3,2,1,1,2,2,3,1,1 0,1,1,2,2,2,1,3,1,1 0,4,2,1,1,2,2,3,1,1 1,10,10,10,2,10,10,5,3,3 1,5,3,5,1,8,10,5,3,1 1,5,4,6,7,9,7,8,10,1 0,1,1,1,1,2,1,2,1,1 1,7,5,3,7,4,10,7,5,5 0,3,1,1,1,2,1,3,1,1 1,8,3,5,4,5,10,1,6,2 0,1,1,1,1,10,1,1,1,1 0,5,1,3,1,2,1,2,1,1 0,2,1,1,1,2,1,3,1,1 1,5,10,8,10,8,10,3,6,3 0,3,1,1,1,2,1,2,2,1 0,3,1,1,1,3,1,2,1,1 0,5,1,1,1,2,2,3,3,1 0,4,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,1,1,1 0,4,1,2,1,2,1,2,1,1 0,3,1,1,1,2,1,1,1,1 0,2,1,1,1,2,1,1,1,1 1,9,5,5,4,4,5,4,3,3 0,1,1,1,1,2,5,1,1,1 0,2,1,1,1,2,1,2,1,1 1,3,4,5,2,6,8,4,1,1 0,1,1,1,1,3,2,2,1,1 0,3,1,1,3,8,1,5,8,1 1,8,8,7,4,10,10,7,8,7 0,1,1,1,1,1,1,3,1,1 1,7,2,4,1,6,10,5,4,3 1,10,10,8,6,4,5,8,10,1 0,4,1,1,1,2,3,1,1,1 0,1,1,1,1,2,1,1,1,1 1,5,5,5,6,3,10,3,1,1 0,1,2,2,1,2,1,2,1,1 0,2,1,1,1,2,1,3,1,1 1,9,9,10,3,6,10,7,10,6 1,10,7,7,4,5,10,5,7,2 0,4,1,1,1,2,1,3,2,1 0,3,1,1,1,2,1,3,1,1 0,1,1,1,2,1,3,1,1,7 0,4,1,1,1,2,2,3,2,1 1,5,6,7,8,8,10,3,10,3 1,10,8,10,10,6,1,3,1,10 0,3,1,1,1,2,1,3,1,1 0,1,1,1,2,1,1,1,1,1 0,3,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,2,1,1 1,6,10,10,10,8,10,10,10,7 1,8,6,5,4,3,10,6,1,1 1,5,8,7,7,10,10,5,7,1 0,2,1,1,1,2,1,3,1,1 1,5,10,10,3,8,1,5,10,3 0,4,1,1,1,2,1,3,1,1 1,5,3,3,3,6,10,3,1,1 0,1,1,1,1,1,1,3,1,1 0,1,1,1,1,2,1,1,1,1 0,6,1,1,1,2,1,3,1,1 1,5,8,8,8,5,10,7,8,1 1,8,7,6,4,4,10,5,1,1 0,2,1,1,1,1,1,3,1,1 1,1,5,8,6,5,8,7,10,1 1,10,5,6,10,6,10,7,7,10 1,5,8,4,10,5,8,9,10,1 0,1,2,3,1,2,1,3,1,1 1,10,10,10,8,6,8,7,10,1 1,7,5,10,10,10,10,4,10,3 0,5,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 0,3,1,1,1,2,1,3,1,1 0,4,1,1,1,2,1,3,1,1 0,8,4,4,5,4,7,7,8,2 0,5,1,1,4,2,1,3,1,1 0,1,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,2,1,1 1,9,7,7,5,5,10,7,8,3 1,10,8,8,4,10,10,8,1,1 0,1,1,1,1,2,1,3,1,1 0,5,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,3,1,1 1,5,10,10,9,6,10,7,10,5 1,10,10,9,3,7,5,3,5,1 0,1,1,1,1,1,1,3,1,1 0,1,1,1,1,1,1,3,1,1 0,5,1,1,1,1,1,3,1,1 1,8,10,10,10,5,10,8,10,6 1,8,10,8,8,4,8,7,7,1 0,1,1,1,1,2,1,3,1,1 1,10,10,10,10,7,10,7,10,4 1,10,10,10,10,3,10,10,6,1 1,8,7,8,7,5,5,5,10,2 0,1,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 1,6,10,7,7,6,4,8,10,2 0,6,1,3,1,2,1,3,1,1 0,1,1,1,2,2,1,3,1,1 1,10,6,4,3,10,10,9,10,1 1,4,1,1,3,1,5,2,1,1 1,7,5,6,3,3,8,7,4,1 1,10,5,5,6,3,10,7,9,2 0,1,1,1,1,2,1,2,1,1 1,10,5,7,4,4,10,8,9,1 1,8,9,9,5,3,5,7,7,1 0,1,1,1,1,1,1,3,1,1 1,10,10,10,3,10,10,9,10,1 1,7,4,7,4,3,7,7,6,1 1,6,8,7,5,6,8,8,9,2 0,8,4,6,3,3,1,4,3,1 1,10,4,5,5,5,10,4,1,1 0,3,3,2,1,3,1,3,6,1 1,10,8,8,2,8,10,4,8,10 1,9,8,8,5,6,2,4,10,4 1,8,10,10,8,6,9,3,10,10 1,10,4,3,2,3,10,5,3,2 0,5,1,3,3,2,2,2,3,1 0,3,1,1,3,1,1,3,1,1 0,2,1,1,1,2,1,3,1,1 0,1,1,1,1,2,5,5,1,1 0,1,1,1,1,2,1,3,1,1 0,5,1,1,2,2,2,3,1,1 1,8,10,10,8,5,10,7,8,1 1,8,4,4,1,2,9,3,3,1 0,4,1,1,1,2,1,3,6,1 0,1,2,2,1,2,1,1,1,1 1,10,4,4,10,2,10,5,3,3 0,6,3,3,5,3,10,3,5,3 1,6,10,10,2,8,10,7,3,3 1,9,10,10,1,10,8,3,3,1 1,5,6,6,2,4,10,3,6,1 0,3,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,3,1,1 0,5,7,7,1,5,8,3,4,1 1,10,5,8,10,3,10,5,1,3 1,5,10,10,6,10,10,10,6,5 1,8,8,9,4,5,10,7,8,1 1,10,4,4,10,6,10,5,5,1 1,7,9,4,10,10,3,5,3,3 0,5,1,4,1,2,1,3,2,1 1,10,10,6,3,3,10,4,3,2 1,3,3,5,2,3,10,7,1,1 1,10,8,8,2,3,4,8,7,8 0,1,1,1,1,2,1,3,1,1 1,8,4,7,1,3,10,3,9,2 0,5,1,1,1,2,1,3,1,1 1,3,3,5,2,3,10,7,1,1 1,7,2,4,1,3,4,3,3,1 0,3,1,1,1,2,1,3,2,1 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 1,10,5,7,3,3,7,3,3,8 0,3,1,1,1,2,1,3,1,1 0,2,1,1,2,2,1,3,1,1 1,1,4,3,10,4,10,5,6,1 1,10,4,6,1,2,10,5,3,1 1,7,4,5,10,2,10,3,8,2 1,8,10,10,10,8,10,10,7,3 1,10,10,10,10,10,10,4,10,10 0,3,1,1,1,3,1,2,1,1 1,6,1,3,1,4,5,5,10,1 1,5,6,6,8,6,10,4,10,4 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,3,1,1 1,10,4,4,6,2,10,2,3,1 1,5,5,7,8,6,10,7,4,1 0,5,3,4,3,4,5,4,7,1 0,8,2,1,1,5,1,1,1,1 1,9,1,2,6,4,10,7,7,2 1,8,4,10,5,4,4,7,10,1 0,1,1,1,1,2,1,3,1,1 1,10,10,10,7,9,10,7,10,10 0,1,1,1,1,2,1,3,1,1 1,8,3,4,9,3,10,3,3,1 1,10,8,4,4,4,10,3,10,4 0,1,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,3,1,1 1,7,8,7,6,4,3,8,8,4 0,3,1,1,1,2,5,5,1,1 0,2,1,1,1,3,1,2,1,1 0,1,1,1,1,2,1,1,1,1 1,8,6,4,10,10,1,3,5,1 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,1,1,2,1,1 1,5,5,5,2,5,10,4,3,1 1,6,8,7,8,6,8,8,9,1 0,1,1,1,1,5,1,3,1,1 0,4,4,4,4,6,5,7,3,1 1,7,6,3,2,5,10,7,4,6 0,3,1,1,1,2,1,3,1,1 1,5,4,6,10,2,10,4,1,1 0,1,1,1,1,2,1,3,1,1 0,3,2,2,1,2,1,2,3,1 1,10,1,1,1,2,10,5,4,1 0,1,1,1,1,2,1,2,1,1 1,8,10,3,2,6,4,3,10,1 1,10,4,6,4,5,10,7,1,1 1,10,4,7,2,2,8,6,1,1 0,5,1,1,1,2,1,3,1,2 0,5,2,2,2,2,1,2,2,1 1,5,4,6,6,4,10,4,3,1 1,8,6,7,3,3,10,3,4,2 0,1,1,1,1,2,1,1,1,1 1,6,5,5,8,4,10,3,4,1 0,1,1,1,1,2,1,3,1,1 0,1,1,1,1,1,1,2,1,1 1,8,5,5,5,2,10,4,3,1 1,10,3,3,1,2,10,7,6,1 0,1,1,1,1,2,1,3,1,1 0,2,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 1,7,6,4,8,10,10,9,5,3 0,1,1,1,1,2,1,1,1,1 0,5,2,2,2,3,1,1,3,1 0,1,1,1,1,1,1,1,3,1 1,3,4,4,10,5,1,3,3,1 1,4,2,3,5,3,8,7,6,1 0,5,1,1,3,2,1,1,1,1 0,2,1,1,1,2,1,3,1,1 0,3,4,5,3,7,3,4,6,1 1,2,7,10,10,7,10,4,9,4 0,1,1,1,1,2,1,2,1,1 0,4,1,1,1,3,1,2,2,1 1,5,3,3,1,3,3,3,3,3 1,8,10,10,7,10,10,7,3,8 1,8,10,5,3,8,4,4,10,3 1,10,3,5,4,3,7,3,5,3 1,6,10,10,10,10,10,8,10,10 1,3,10,3,10,6,10,5,1,4 0,3,2,2,1,4,3,2,1,1 0,4,4,4,2,2,3,2,1,1 0,2,1,1,1,2,1,3,1,1 0,2,1,1,1,2,1,2,1,1 1,6,10,10,10,8,10,7,10,7 1,5,8,8,10,5,10,8,10,3 0,1,1,3,1,2,1,1,1,1 0,1,1,3,1,1,1,2,1,1 0,4,3,2,1,3,1,2,1,1 0,1,1,3,1,2,1,1,1,1 0,4,1,2,1,2,1,2,1,1 0,5,1,1,2,2,1,2,1,1 0,3,1,2,1,2,1,2,1,1 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,2,1,1 0,1,1,1,1,1,1,2,1,1 0,3,1,1,4,3,1,2,2,1 0,5,3,4,1,4,1,3,1,1 0,1,1,1,1,2,1,1,1,1 1,10,6,3,6,4,10,7,8,4 0,3,2,2,2,2,1,3,2,1 0,2,1,1,1,2,1,1,1,1 0,2,1,1,1,2,1,1,1,1 0,3,3,2,2,3,1,1,2,3 1,7,6,6,3,2,10,7,1,1 0,5,3,3,2,3,1,3,1,1 0,2,1,1,1,2,1,2,2,1 0,5,1,1,1,3,2,2,2,1 0,1,1,1,2,2,1,2,1,1 1,10,8,7,4,3,10,7,9,1 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,1,1,1,1,1 0,1,2,3,1,2,1,2,1,1 0,3,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,3,1,1 0,4,1,1,1,2,1,1,1,1 0,3,2,1,1,2,1,2,2,1 0,1,2,3,1,2,1,1,1,1 1,3,10,8,7,6,9,9,3,8 0,3,1,1,1,2,1,1,1,1 0,5,3,3,1,2,1,2,1,1 0,3,1,1,1,2,4,1,1,1 0,1,2,1,3,2,1,1,2,1 0,1,1,1,1,2,1,2,1,1 0,4,2,2,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 0,2,3,2,2,2,2,3,1,1 0,3,1,2,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 1,10,10,10,6,8,4,8,5,1 0,5,1,2,1,2,1,3,1,1 1,8,5,6,2,3,10,6,6,1 0,3,3,2,6,3,3,3,5,1 1,8,7,8,5,10,10,7,2,1 0,1,1,1,1,2,1,2,1,1 0,5,2,2,2,2,2,3,2,2 0,2,3,1,1,5,1,1,1,1 0,3,2,2,3,2,3,3,1,1 1,10,10,10,7,10,10,8,2,1 0,4,3,3,1,2,1,3,3,1 0,5,1,3,1,2,1,2,1,1 0,3,1,1,1,2,1,1,1,1 1,9,10,10,10,10,10,10,10,1 0,5,3,6,1,2,1,1,1,1 1,8,7,8,2,4,2,5,10,1 0,1,1,1,1,2,1,2,1,1 0,2,1,1,1,2,1,2,1,1 0,1,3,1,1,2,1,2,2,1 0,5,1,1,3,4,1,3,2,1 0,5,1,1,1,2,1,2,2,1 0,3,2,2,3,2,1,1,1,1 0,6,9,7,5,5,8,4,2,1 1,10,8,10,1,3,10,5,1,1 1,10,10,10,1,6,1,2,8,1 0,4,1,1,1,2,1,1,1,1 0,4,1,3,3,2,1,1,1,1 0,5,1,1,1,2,1,1,1,1 1,10,4,3,10,4,10,10,1,1 0,5,2,2,4,2,4,1,1,1 0,1,1,1,3,2,3,1,1,1 0,1,1,1,1,2,2,1,1,1 0,5,1,1,6,3,1,2,1,1 0,2,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,5,1,1,1,2,1,1,1,1 0,1,1,1,1,1,1,1,1,1 1,5,7,9,8,6,10,8,10,1 0,4,1,1,3,1,1,2,1,1 0,5,1,1,1,2,1,1,1,1 0,3,1,1,3,2,1,1,1,1 1,4,5,5,8,6,10,10,7,1 0,2,3,1,1,3,1,1,1,1 1,10,2,2,1,2,6,1,1,2 1,10,6,5,8,5,10,8,6,1 1,8,8,9,6,6,3,10,10,1 0,5,1,2,1,2,1,1,1,1 0,5,1,3,1,2,1,1,1,1 0,5,1,1,3,2,1,1,1,1 0,3,1,1,1,2,5,1,1,1 0,6,1,1,3,2,1,1,1,1 0,4,1,1,1,2,1,1,2,1 0,4,1,1,1,2,1,1,1,1 1,10,9,8,7,6,4,7,10,3 1,10,6,6,2,4,10,9,7,1 1,6,6,6,5,4,10,7,6,2 0,4,1,1,1,2,1,1,1,1 0,1,1,2,1,2,1,2,1,1 0,3,1,1,1,1,1,2,1,1 0,6,1,1,3,2,1,1,1,1 0,6,1,1,1,1,1,1,1,1 0,4,1,1,1,2,1,1,1,1 0,5,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,1,1,1 0,4,1,2,1,2,1,1,1,1 0,4,1,1,1,2,1,1,1,1 0,5,2,1,1,2,1,1,1,1 1,4,8,7,10,4,10,7,5,1 0,5,1,1,1,1,1,1,1,1 0,5,3,2,4,2,1,1,1,1 1,9,10,10,10,10,5,10,10,10 1,8,7,8,5,5,10,9,10,1 0,5,1,2,1,2,1,1,1,1 0,1,1,1,3,1,3,1,1,1 0,3,1,1,1,1,1,2,1,1 1,10,10,10,10,6,10,8,1,5 1,3,6,4,10,3,3,3,4,1 1,6,3,2,1,3,4,4,1,1 0,1,1,1,1,2,1,1,1,1 1,5,8,9,4,3,10,7,1,1 0,4,1,1,1,1,1,2,1,1 1,5,10,10,10,6,10,6,5,2 0,5,1,2,10,4,5,2,1,1 0,3,1,1,1,1,1,2,1,1 0,1,1,1,1,1,1,1,1,1 0,4,2,1,1,2,1,1,1,1 0,4,1,1,1,2,1,2,1,1 0,4,1,1,1,2,1,2,1,1 0,6,1,1,1,2,1,3,1,1 0,4,1,1,1,2,1,2,1,1 0,4,1,1,2,2,1,2,1,1 0,4,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,1,1,1 0,3,3,1,1,2,1,1,1,1 1,8,10,10,10,7,5,4,8,7 0,1,1,1,1,2,4,1,1,1 0,5,1,1,1,2,1,1,1,1 0,2,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,5,1,1,1,2,1,2,1,1 0,5,1,1,1,2,1,1,1,1 0,3,1,1,1,1,1,2,1,1 1,6,6,7,10,3,10,8,10,2 1,4,10,4,7,3,10,9,10,1 0,1,1,1,1,1,1,1,1,1 0,1,1,1,1,1,1,2,1,1 0,3,1,2,2,2,1,1,1,1 1,4,7,8,3,4,10,9,1,1 0,1,1,1,1,3,1,1,1,1 0,4,1,1,1,3,1,1,1,1 1,10,4,5,4,3,5,7,3,1 1,7,5,6,10,4,10,5,3,1 0,3,1,1,1,2,1,2,1,1 0,3,1,1,2,2,1,1,1,1 0,4,1,1,1,2,1,1,1,1 0,4,1,1,1,2,1,3,1,1 0,6,1,3,2,2,1,1,1,1 0,4,1,1,1,1,1,2,1,1 1,7,4,4,3,4,10,6,9,1 0,4,2,2,1,2,1,2,1,1 0,1,1,1,1,1,1,3,1,1 0,3,1,1,1,2,1,2,1,1 0,2,1,1,1,2,1,2,1,1 0,1,1,3,2,2,1,3,1,1 0,5,1,1,1,2,1,3,1,1 0,5,1,2,1,2,1,3,1,1 0,4,1,1,1,2,1,2,1,1 0,6,1,1,1,2,1,2,1,1 0,5,1,1,1,2,2,2,1,1 0,3,1,1,1,2,1,1,1,1 0,5,3,1,1,2,1,1,1,1 0,4,1,1,1,2,1,2,1,1 0,2,1,3,2,2,1,2,1,1 0,5,1,1,1,2,1,2,1,1 1,6,10,10,10,4,10,7,10,1 0,2,1,1,1,1,1,1,1,1 0,3,1,1,1,1,1,1,1,1 1,7,8,3,7,4,5,7,8,2 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 0,3,2,2,2,2,1,4,2,1 0,4,4,2,1,2,5,2,1,2 0,3,1,1,1,2,1,1,1,1 0,4,3,1,1,2,1,4,8,1 0,5,2,2,2,1,1,2,1,1 0,5,1,1,3,2,1,1,1,1 0,2,1,1,1,2,1,2,1,1 0,5,1,1,1,2,1,2,1,1 0,5,1,1,1,2,1,3,1,1 0,5,1,1,1,2,1,3,1,1 0,1,1,1,1,2,1,3,1,1 0,3,1,1,1,2,1,2,1,1 0,4,1,1,1,2,1,3,2,1 1,5,7,10,10,5,10,10,10,1 0,3,1,2,1,2,1,3,1,1 0,4,1,1,1,2,3,2,1,1 1,8,4,4,1,6,10,2,5,2 1,10,10,8,10,6,5,10,3,1 1,8,10,4,4,8,10,8,2,1 1,7,6,10,5,3,10,9,10,2 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 1,10,9,7,3,4,2,7,7,1 0,5,1,2,1,2,1,3,1,1 0,5,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,3,1,1 0,5,1,2,1,2,1,2,1,1 1,5,7,10,6,5,10,7,5,1 1,6,10,5,5,4,10,6,10,1 0,3,1,1,1,2,1,1,1,1 0,5,1,1,6,3,1,1,1,1 0,1,1,1,1,2,1,1,1,1 1,8,10,10,10,6,10,10,10,1 0,5,1,1,1,2,1,2,2,1 1,9,8,8,9,6,3,4,1,1 0,5,1,1,1,2,1,1,1,1 1,4,10,8,5,4,1,10,1,1 1,2,5,7,6,4,10,7,6,1 1,10,3,4,5,3,10,4,1,1 0,5,1,2,1,2,1,1,1,1 1,4,8,6,3,4,10,7,1,1 0,5,1,1,1,2,1,2,1,1 0,4,1,2,1,2,1,2,1,1 0,5,1,3,1,2,1,3,1,1 0,3,1,1,1,2,1,2,1,1 0,5,2,4,1,1,1,1,1,1 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,1,1,2,1,1 0,4,1,1,1,2,1,2,1,1 1,5,4,6,8,4,1,8,10,1 1,5,3,2,8,5,10,8,1,2 1,10,5,10,3,5,8,7,8,3 0,4,1,1,2,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 1,5,10,10,10,10,10,10,1,1 0,5,1,1,1,2,1,1,1,1 1,10,4,3,10,3,10,7,1,2 1,5,10,10,10,5,2,8,5,1 1,8,10,10,10,6,10,10,10,10 0,2,3,1,1,2,1,2,1,1 0,2,1,1,1,1,1,2,1,1 0,4,1,3,1,2,1,2,1,1 0,3,1,1,1,2,1,2,1,1 0,4,1,1,1,2,1,2,1,1 0,5,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,2,1,1 0,6,3,3,3,3,2,6,1,1 0,7,1,2,3,2,1,2,1,1 0,1,1,1,1,2,1,1,1,1 0,5,1,1,2,1,1,2,1,1 0,3,1,3,1,3,4,1,1,1 1,4,6,6,5,7,6,7,7,3 0,2,1,1,1,2,5,1,1,1 0,2,1,1,1,2,1,1,1,1 0,4,1,1,1,2,1,1,1,1 0,6,2,3,1,2,1,1,1,1 0,5,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,1,1,1 1,8,7,4,4,5,3,5,10,1 0,3,1,1,1,2,1,1,1,1 0,3,1,4,1,2,1,1,1,1 1,10,10,7,8,7,1,10,10,3 0,4,2,4,3,2,2,2,1,1 0,4,1,1,1,2,1,1,1,1 0,5,1,1,3,2,1,1,1,1 0,4,1,1,3,2,1,1,1,1 0,3,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,2,1,1 0,1,1,1,1,2,1,1,1,1 0,2,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,2,1,1 0,1,2,2,1,2,1,1,1,1 0,1,1,1,3,2,1,1,1,1 1,5,10,10,10,10,2,10,10,10 0,3,1,1,1,2,1,2,1,1 0,3,1,1,2,3,4,1,1,1 0,1,2,1,3,2,1,2,1,1 0,5,1,1,1,2,1,2,2,1 0,4,1,1,1,2,1,2,1,1 0,3,1,1,1,2,1,3,1,1 0,3,1,1,1,2,1,2,1,1 0,5,1,1,1,2,1,2,1,1 0,5,4,5,1,8,1,3,6,1 1,7,8,8,7,3,10,7,2,3 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,2,1,1 0,4,1,1,1,2,1,3,1,1 0,1,1,3,1,2,1,2,1,1 0,1,1,3,1,2,1,2,1,1 0,3,1,1,3,2,1,2,1,1 0,1,1,1,1,2,1,1,1,1 0,5,2,2,2,2,1,1,1,2 0,3,1,1,1,2,1,3,1,1 1,5,7,4,1,6,1,7,10,3 1,5,10,10,8,5,5,7,10,1 1,3,10,7,8,5,8,7,4,1 0,3,2,1,2,2,1,3,1,1 0,2,1,1,1,2,1,3,1,1 0,5,3,2,1,3,1,1,1,1 0,1,1,1,1,2,1,2,1,1 0,4,1,4,1,2,1,1,1,1 0,1,1,2,1,2,1,2,1,1 0,5,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,2,1,1,1,2,1,1,1,1 1,10,10,10,10,5,10,10,10,7 1,5,10,10,10,4,10,5,6,3 0,5,1,1,1,2,1,3,2,1 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,2,3,1 0,4,1,1,1,2,1,1,1,1 0,1,1,1,1,2,1,1,1,8 0,1,1,1,3,2,1,1,1,1 1,5,10,10,5,4,5,4,4,1 0,3,1,1,1,2,1,1,1,1 0,3,1,1,1,2,1,2,1,2 0,3,1,1,1,3,2,1,1,1 0,2,1,1,1,2,1,1,1,1 1,5,10,10,3,7,3,8,10,2 1,4,8,6,4,3,4,10,6,1 1,4,8,8,5,4,5,10,4,1 -------------------------------------------------------------------------------- /data/haberman_processed.csv: -------------------------------------------------------------------------------- 1 | "AliveAfter5Yrs","Age","NumberOfNodes","YrsSinceFirstOperations" 1,30,1,6 1,30,3,4 1,30,0,7 1,31,2,1 1,31,4,7 1,33,10,0 1,33,0,2 0,34,0,1 0,34,9,8 1,34,30,0 1,34,1,2 1,34,10,3 1,34,7,9 1,34,0,2 1,35,13,6 1,35,0,5 1,36,1,2 1,36,0,11 1,37,0,2 1,37,0,5 1,37,0,0 1,37,6,1 1,37,15,2 1,37,0,5 0,38,21,11 1,38,2,1 1,38,0,2 1,38,0,2 1,38,3,4 1,38,1,6 1,38,0,8 1,38,11,8 1,38,1,2 1,38,5,9 0,39,0,8 1,39,0,5 1,39,0,9 1,39,0,0 1,39,2,1 1,39,4,5 1,40,2,0 1,40,0,0 1,40,0,7 0,41,23,2 0,41,0,6 0,41,0,9 1,41,0,0 1,41,8,1 1,41,0,1 1,41,0,6 1,41,8,11 1,41,0,7 1,41,0,7 0,42,1,11 0,42,0,1 1,42,0,0 1,42,1,2 1,42,2,1 1,42,4,3 1,42,20,4 1,42,0,7 1,42,1,5 0,43,52,0 0,43,2,1 0,43,0,6 0,43,0,6 1,43,14,5 1,43,2,6 1,43,3,6 1,43,0,2 1,43,2,5 1,43,0,7 1,43,4,8 0,44,6,6 0,44,9,0 0,44,19,5 1,44,0,3 1,44,1,5 1,44,0,3 1,44,16,9 0,45,6,7 0,45,0,8 0,45,1,9 1,45,0,2 1,45,0,9 1,45,14,1 1,45,0,6 1,45,0,10 1,45,1,9 0,46,2,0 0,46,3,11 0,46,5,4 0,46,20,7 1,46,0,4 1,46,3,0 1,46,0,5 0,47,23,5 0,47,0,4 0,47,0,7 1,47,0,3 1,47,6,5 1,47,0,8 1,47,0,9 1,47,3,0 1,47,4,2 1,47,4,10 1,47,12,8 0,48,11,0 0,48,11,0 0,48,7,9 1,48,8,3 1,48,2,4 1,48,0,6 1,48,0,8 0,49,0,5 0,49,10,6 1,49,1,3 1,49,0,4 1,49,0,8 1,49,1,2 1,49,1,4 1,49,3,5 1,49,0,3 1,49,1,9 0,50,13,5 0,50,0,6 1,50,0,1 1,50,6,3 1,50,0,3 1,50,1,5 1,50,1,0 1,50,2,1 1,50,0,3 1,50,0,6 1,50,4,7 1,50,1,8 0,51,13,1 0,51,3,1 1,51,7,6 1,51,1,1 1,51,0,7 1,51,1,8 0,52,3,11 0,52,2,1 0,52,3,4 0,52,4,8 1,52,0,3 1,52,4,5 1,52,0,11 1,52,4,2 1,52,5,2 1,52,0,4 1,52,1,4 1,52,0,6 1,52,0,7 1,52,0,10 0,53,4,0 0,53,1,7 0,53,3,1 0,53,9,2 0,53,24,5 0,53,12,7 1,53,1,0 1,53,1,2 1,53,2,2 1,53,1,3 1,53,0,5 0,54,11,2 0,54,23,7 0,54,5,7 0,54,7,10 1,54,7,1 1,54,3,2 1,54,0,8 1,54,46,9 1,54,0,4 1,54,7,11 1,54,19,5 1,54,1,0 1,54,0,4 0,55,6,5 0,55,15,10 1,55,1,0 1,55,0,0 1,55,1,0 1,55,18,8 1,55,0,8 1,55,3,11 1,55,22,11 1,55,1,9 0,56,9,7 0,56,3,8 1,56,0,2 1,56,2,8 1,56,1,8 1,56,0,9 1,56,0,2 0,57,5,3 0,57,14,4 0,57,1,6 1,57,9,6 1,57,0,11 1,57,0,3 1,57,0,4 1,57,0,5 1,57,0,6 1,57,0,6 1,57,0,9 1,58,0,1 1,58,3,2 1,58,1,3 1,58,0,9 1,58,0,0 1,58,3,0 1,58,2,3 0,59,35,4 1,59,0,2 1,59,0,5 1,59,1,6 1,59,4,6 1,59,0,6 1,59,7,6 1,59,3,9 0,60,17,1 0,60,0,7 1,60,1,3 1,60,2,9 1,60,25,3 1,60,0,6 0,61,5,4 0,61,0,7 0,61,1,10 1,61,0,1 1,61,0,1 1,61,0,6 1,61,8,7 1,61,0,10 1,61,0,1 0,62,13,1 0,62,0,0 0,62,19,7 1,62,6,4 1,62,0,8 1,62,0,8 1,62,0,0 0,63,1,2 1,63,0,3 1,63,0,4 1,63,0,5 1,63,0,5 1,63,0,8 1,63,9,3 1,63,28,3 1,64,0,0 1,64,22,7 1,64,0,8 1,64,0,3 1,64,0,10 0,65,0,0 0,65,2,3 0,65,22,4 0,65,15,8 1,65,0,0 1,65,0,6 1,65,0,9 1,65,2,1 1,65,0,6 1,65,1,9 0,66,0,0 0,66,13,3 1,66,0,0 1,66,1,0 1,66,0,10 0,67,8,6 0,67,1,5 1,67,0,8 1,67,0,8 1,67,0,3 1,67,0,7 1,68,0,9 1,68,0,10 0,69,8,9 1,69,0,2 1,69,0,7 1,69,0,8 0,70,0,0 0,70,4,0 1,70,14,8 1,70,0,9 1,70,0,10 1,70,8,1 1,70,0,5 1,71,2,10 0,72,0,5 1,72,0,0 1,72,0,6 1,72,3,9 1,73,0,4 1,73,0,10 0,74,3,7 1,74,0,5 1,75,1,4 1,76,0,9 1,77,3,7 0,78,1,7 0,83,2,0 -------------------------------------------------------------------------------- /data/heart_processed.csv: -------------------------------------------------------------------------------- 1 | "Disease","FastingBloodSugar_ge_120","ExerciseAngina","ExerciseSTDepression","NumVesselsByFlourosopy","Male","Female","ChestPain_eq_typicalangina","ChestPain_eq_asymptomatic","ChestPain_eq_nonanginal","ChestPain_eq_atypicalangina","ExerciseSTPeakSlope_eq_Down","ExerciseSTPeakSlope_eq_Flat","ExerciseSTPeakSlope_eq_Up","Thal_eq_FixedDefect","Thal_eq_Normal","Thal_eq_ReversableDefect","RestECG_eq_likely_v_hypertrophy","RestECG_eq_normal","RestECG_eq_st_abnormality","Cholesterol_lt_200","Cholesterol_200_to_240","Cholesterol_gt_240","RestBP_Normal","RestBP_PreHypertension","RestBP_Hypertension_Stage_1","RestBP_Hypertension_Stage_2","RestBP_HypertensiveCrisis","MaxExerciseHRTargetRatio","Age_lt_30","Age_geq_30","Age_geq_45","Age_geq_60" 0,1,0,2.3,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0.0466666666666666,0,1,1,1 1,0,1,1.5,3,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0.416666666666667,0,1,1,1 1,0,1,2.6,2,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0.186046511627907,0,1,1,1 0,0,0,3.5,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0213903743315508,0,1,0,0 0,0,0,1.4,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.0406976744186047,0,1,0,0 0,0,0,0.8,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.0786516853932584,0,1,1,0 1,0,0,3.6,2,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0,-0.0125,0,1,1,1 0,0,1,0.6,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,1,0 1,0,0,1.4,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.0680272108843538,0,1,1,1 1,1,1,3.1,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.0774193548387097,0,1,1,0 0,0,0,0.4,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,1,0,0,0.101351351351351,0,1,1,0 0,0,0,1.3,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0.0718954248366013,0,1,1,0 1,1,1,0.6,1,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,0.154929577464789,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.0173410404624277,0,1,0,0 0,1,0,0.5,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0.037037037037037,0,1,1,0 0,0,0,1.6,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,-0.0632183908045977,0,1,1,0 1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.0238095238095237,0,1,1,0 0,0,0,1.2,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0.0375000000000001,0,1,1,0 0,0,0,0.2,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.237410071942446,0,1,1,0 0,0,0,0.6,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,1,0 0,0,1,1.8,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0.0833333333333333,0,1,1,1 0,1,0,1,0,0,1,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,0 1,0,0,1.8,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0125,0,1,1,0 1,0,0,3.2,2,1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,-0.0635838150289018,0,1,1,0 1,0,1,2.4,2,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0.212121212121212,0,1,1,1 0,0,0,1.6,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0759493670886076,0,1,1,0 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0581395348837209,0,1,1,0 0,0,0,2.6,0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0.350877192982456,0,1,1,1 0,0,0,1.5,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0.0350877192982457,0,1,0,0 1,0,1,2,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0.578947368421053,0,1,0,0 0,0,0,1.8,2,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,1,1 1,1,1,1.4,2,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,1,1,1 1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,-0.0126582278481012,0,1,1,1 0,0,0,0.5,0,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,1,0 0,0,1,0.4,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.0167597765363129,0,1,0,0 0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0 1,0,1,2.5,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0,0.475,0,1,0,0 1,0,1,0.6,1,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0.455357142857143,0,1,1,0 1,0,1,1.2,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.25,0,1,1,0 0,1,1,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0.160583941605839,0,1,1,1 1,0,0,1,3,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.359649122807018,0,1,1,1 0,0,1,1.4,0,1,0,1,0,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0.0112359550561798,0,1,0,0 0,0,0,0.4,2,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,1,0,-0.0802469135802469,0,1,1,1 0,1,0,1.6,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0.0254777070063694,0,1,1,0 1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.0591715976331361,0,1,1,1 1,0,0,2.5,1,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,-0.0181818181818182,0,1,1,0 0,0,0,0.6,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.373983739837398,0,1,1,0 1,0,0,2.6,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.328125,0,1,1,0 0,1,0,0.8,1,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,-0.0127388535031847,0,1,1,1 0,1,0,1.2,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0.0986842105263157,0,1,1,0 0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.0654761904761905,0,1,0,0 0,0,0,0.4,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0.107142857142857,0,1,1,1 1,0,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.150326797385621,0,1,0,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,-0.0638297872340425,0,1,0,0 1,0,1,1.4,1,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.111111111111111,0,1,1,1 1,0,1,2.2,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.522935779816514,0,1,1,0 1,0,0,0.6,1,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0.0429447852760736,0,1,1,0 1,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0.132911392405063,0,1,0,0 0,0,0,0.5,1,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0921052631578947,0,1,1,0 0,0,1,1.4,1,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.352,0,1,1,0 1,0,1,1.2,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.190140845070423,0,1,1,0 0,0,1,1.4,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0.0874999999999999,0,1,1,0 1,0,1,2.2,3,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0.236641221374046,0,1,1,0 0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0235294117647059,0,1,1,0 1,0,0,1.4,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0.469026548672566,0,1,1,0 1,0,1,2.8,2,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.126760563380282,0,1,1,1 1,0,0,3,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0.032258064516129,0,1,1,1 0,0,0,1.6,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.0060606060606061,0,1,1,0 1,0,1,3.4,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0.15,0,1,1,0 1,0,0,3.6,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0.183673469387755,0,1,1,0 0,0,0,0.8,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0.0472972972972974,0,1,1,1 1,1,0,0.2,2,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,-0.0613496932515337,0,1,1,1 1,0,1,1.8,2,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.595959595959596,0,1,1,1 1,0,0,0.6,2,1,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,1,0,0,0,0,-0.0189873417721519,0,1,1,1 1,0,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,0,0,0,-0.00564971751412424,0,1,0,0 0,0,0,0.8,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0.0264900662251655,0,1,1,1 1,0,1,2.8,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.134751773049645,0,1,1,1 0,0,0,1.5,1,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0.190140845070423,0,1,1,0 0,0,0,0.2,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.0444444444444444,0,1,1,0 1,0,1,0.8,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.459459459459459,0,1,1,0 0,0,1,3,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0.182432432432432,0,1,1,0 0,0,0,0.4,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.167832167832168,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,-0.00549450549450547,0,1,0,0 1,1,1,1.6,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0.0133333333333334,0,1,1,1 0,0,0,0.2,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0232558139534884,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,-0.0222222222222223,0,1,0,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.108974358974359,0,1,1,0 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0.452173913043478,0,1,1,0 0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.04375,0,1,1,0 0,0,0,0.5,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.134228187919463,0,1,1,0 0,0,0,0.4,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0198675496688743,0,1,1,1 1,0,0,6.2,3,0,1,0,1,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0.0896551724137931,0,1,1,1 0,0,0,1.8,3,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0.0821917808219179,0,1,1,1 0,0,0,0.6,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.00571428571428578,0,1,0,0 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.0872093023255814,0,1,1,1 1,0,1,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.0434782608695652,0,1,1,0 1,0,1,1.2,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0.133802816901408,0,1,1,0 1,0,0,2.6,2,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.0191082802547771,0,1,1,1 0,0,0,0.8,1,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0632911392405062,0,1,1,0 0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,-0.0752688172043011,0,1,1,0 0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,-0.0540540540540541,0,1,1,0 0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0.0689655172413792,0,1,0,0 0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0251572327044025,0,1,1,0 0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.146153846153846,0,1,1,1 1,0,0,2,3,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0.230215827338129,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0.0641025641025641,0,1,1,0 1,0,1,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,-0.00617283950617287,0,1,1,0 1,0,0,0.4,1,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0.0866666666666667,0,1,1,0 1,0,1,3.6,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.135714285714286,0,1,1,1 1,0,0,1.2,0,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.292857142857143,0,1,0,0 1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.0890410958904109,0,1,1,1 1,1,1,1.2,1,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.138888888888889,0,1,1,0 0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-0.115789473684211,0,1,1,0 1,1,1,3,0,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.301470588235294,0,1,0,0 1,0,0,1.2,1,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.628865979381443,0,1,1,1 0,0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,0.356060606060606,0,1,0,0 0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,-0.0181818181818182,0,1,1,0 0,0,0,1.4,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.0164835164835164,0,1,0,0 1,1,1,1.8,3,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.189393939393939,0,1,1,1 1,0,0,2.8,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.220472440944882,0,1,1,1 1,1,1,0,2,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.146666666666667,0,1,1,0 1,0,0,4,3,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.0194805194805194,0,1,1,1 0,0,1,1.2,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.181818181818182,0,1,1,0 1,0,1,5.6,0,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0.486486486486486,0,1,1,0 1,1,0,1.4,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.109195402298851,0,1,1,1 0,0,0,0.6,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0 1,1,1,4,2,0,1,0,1,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0.233082706766917,0,1,1,0 1,0,1,2.8,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.317460317460317,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0352941176470589,0,1,0,0 0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.0306748466257669,0,1,1,1 0,0,0,0.4,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.129251700680272,0,1,1,0 0,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.0974025974025974,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,-0.0544554455445545,1,0,0,0 0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,-0.0913978494623656,0,1,1,0 0,0,0,0.2,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0727272727272728,0,1,0,0 0,0,0,1.4,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0248447204968945,0,1,1,0 1,0,1,2.6,0,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0.2,0,1,1,1 1,0,0,1.4,1,1,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.533980582524272,0,1,1,1 1,0,1,1.6,0,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0.423076923076923,0,1,0,0 0,1,0,2.4,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0180722891566265,0,1,1,0 0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,-0.0182926829268293,0,1,1,0 1,0,0,0.2,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0.0125786163522013,0,1,1,0 0,1,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.0869565217391305,0,1,1,0 1,0,1,1.8,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.190839694656489,0,1,1,1 0,0,1,0.6,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0.051948051948052,0,1,1,0 1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0.138157894736842,0,1,1,0 1,1,0,1,3,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0.314516129032258,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,0,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0294117647058822,0,1,1,0 0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1 0,1,0,1.2,0,1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,-0.0561797752808989,0,1,1,0 0,0,0,0.6,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.459016393442623,0,1,0,0 0,0,0,1.6,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,-0.04375,0,1,1,1 1,0,1,0.8,1,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0.137931034482759,0,1,1,0 1,0,1,2.2,1,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.625,0,1,1,1 1,0,0,2.4,3,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.376146788990826,0,1,1,1 1,0,1,1.6,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,-0.023121387283237,0,1,1,0 1,0,0,0,2,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,-0.0526315789473685,0,1,1,0 1,0,0,1.2,2,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,-0.0588235294117647,0,1,1,1 0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0.00662251655629142,0,1,1,1 0,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,0,0.115384615384615,0,1,1,0 1,0,1,0,3,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.117283950617284,0,1,1,1 0,0,0,1.6,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.0506329113924051,0,1,1,0 0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.327868852459016,0,1,1,0 0,1,0,0,2,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0171428571428571,0,1,1,0 0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,-0.0297619047619048,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.00591715976331364,0,1,1,0 0,1,1,0,1,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0440251572327044,0,1,1,0 1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.185897435897436,0,1,0,0 0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.268115942028986,0,1,1,0 1,0,1,2.9,1,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0.339285714285714,0,1,1,1 0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.504504504504504,0,1,1,0 1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0.125874125874126,0,1,1,0 0,0,0,1.2,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0.00636942675159236,0,1,1,1 1,0,0,2,2,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0.181818181818182,0,1,1,1 1,0,1,1.2,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0.852272727272727,0,1,1,0 0,1,0,0.1,3,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.142857142857143,0,1,1,0 1,0,1,2.1,1,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0.561904761904762,0,1,1,0 0,0,0,1.9,1,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0925925925925926,0,1,0,0 0,1,0,0,3,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.0346820809248555,0,1,1,0 1,0,0,0.5,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.036144578313253,0,1,1,0 1,0,1,1.9,2,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.0933333333333333,0,1,1,0 0,0,0,0.8,2,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0 0,0,0,4.2,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0.110344827586207,0,1,1,0 1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,-0.00621118012422361,0,1,1,1 0,0,0,0,2,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,-0.122905027932961,0,1,1,1 0,1,0,0.8,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,-0.0824742268041238,0,1,0,0 1,0,1,0,3,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0.283333333333333,0,1,1,1 1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,1,0,0,0,1,1,-0.148717948717949,0,1,1,0 1,0,0,2,3,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.0342465753424657,0,1,1,1 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.0429447852760736,0,1,1,0 1,0,1,4.2,3,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0.385245901639344,0,1,1,0 1,1,1,0.1,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.237762237762238,0,1,0,0 1,1,0,1.9,3,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.490566037735849,0,1,1,1 0,0,0,1.5,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.321739130434783,0,1,1,1 1,0,1,0.9,2,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.224,0,1,1,1 0,1,0,0.1,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,0.152671755725191,0,1,1,1 0,0,1,0.2,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.151315789473684,0,1,1,0 0,0,0,1.1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0493827160493827,0,1,1,0 1,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0.288,0,1,1,0 0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.0691823899371069,0,1,1,0 0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0.0129870129870129,0,1,1,1 0,1,0,0.2,1,1,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,-0.0578034682080925,0,1,1,0 0,0,0,0.2,0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0.172932330827068,0,1,1,1 0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.0993788819875776,0,1,0,0 1,0,1,0,3,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0.19047619047619,0,1,1,0 1,0,1,3,2,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.246153846153846,0,1,1,0 1,0,1,0.9,0,1,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.349206349206349,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.064516129032258,0,1,1,0 1,0,1,1.4,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0.025974025974026,0,1,1,1 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0764705882352941,0,1,0,0 1,0,1,3.8,0,1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0 0,0,0,2,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.0654761904761905,0,1,0,0 1,1,1,1,2,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,-0.0666666666666667,0,1,1,1 1,0,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.05,0,1,1,0 0,0,0,1.9,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0,0.0123456790123457,0,1,1,0 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.0116279069767442,0,1,1,0 0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.144736842105263,0,1,1,0 0,0,0,2,2,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.278688524590164,0,1,1,1 0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,-0.115384615384615,0,1,1,0 0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.0406976744186047,0,1,0,0 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,-0.00598802395209586,0,1,1,0 0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.011173184357542,0,1,0,0 1,0,1,2,2,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.757894736842105,0,1,1,0 1,0,1,1.8,2,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,-0.0710059171597633,0,1,1,1 0,0,0,0.7,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,-0.03125,0,1,0,0 0,0,0,0.1,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.20979020979021,0,1,1,0 0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,-0.11046511627907,0,1,1,1 1,0,1,0,1,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0.537037037037037,0,1,1,0 1,0,1,0.1,1,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0.166666666666667,0,1,1,1 0,0,0,0.1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,-0.00591715976331364,0,1,1,0 1,0,1,3.4,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0.41025641025641,0,1,1,0 1,0,0,0.8,3,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0.357142857142857,0,1,1,0 0,0,1,0.2,1,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.206611570247934,0,1,1,1 0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0.01840490797546,0,1,1,0 1,0,1,3.2,2,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.431034482758621,0,1,1,0 1,1,1,1.6,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.592233009708738,0,1,1,0 1,0,0,0.8,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0.208333333333333,0,1,1,0 0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0555555555555556,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0987654320987654,0,1,0,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.169934640522876,0,1,0,0 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0981595092024541,0,1,0,0 0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0.0490797546012269,0,1,1,0 1,0,0,2.6,2,1,0,1,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.096551724137931,0,1,1,1 0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.666666666666667,0,1,1,1 1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1.15492957746479,0,1,1,1 1,0,0,0.1,1,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0.0384615384615385,0,1,1,0 1,0,1,1,1,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0.466101694915254,0,1,1,0 1,0,0,1,2,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,1,0 0,1,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0.128571428571429,0,1,1,1 0,0,1,1.5,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,0.293650793650794,0,1,1,0 1,0,0,2,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0.542857142857143,0,1,1,0 0,0,1,0.2,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.485714285714286,0,1,1,1 0,0,0,0.6,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0764331210191083,0,1,1,0 0,0,0,1.2,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,-0.0220994475138122,0,1,0,0 0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0289017341040463,0,1,0,0 0,0,0,0.3,2,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0.0774647887323943,0,1,1,1 0,0,0,1.1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0.241379310344828,0,1,1,1 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0.048951048951049,0,1,1,1 1,0,0,0.3,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0.156028368794326,0,1,1,0 0,0,0,0.3,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0.181208053691275,0,1,0,0 1,1,0,0,2,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0.0657894736842106,0,1,1,0 0,0,0,0.9,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,-0.064327485380117,0,1,1,1 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.0414201183431953,0,1,0,0 1,0,1,3.6,1,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0.272,0,1,1,1 1,0,1,1.8,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0.424,0,1,0,0 1,1,1,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0.0769230769230769,0,1,1,0 1,1,0,2.2,1,1,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,0.201492537313433,0,1,1,0 1,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,-0.00552486187845302,0,1,0,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.186666666666667,0,1,0,0 1,0,1,1.9,1,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.152173913043478,0,1,1,1 0,0,0,2.3,0,1,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0.115942028985507,0,1,1,1 1,0,1,1.8,2,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0.45,0,1,1,0 0,0,0,1.6,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0.192,0,1,1,1 1,0,0,0.8,2,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.00617283950617287,0,1,1,0 0,0,0,0.6,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,1,0,0.00645161290322571,0,1,1,1 0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0.013157894736842,0,1,1,1 0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0.190789473684211,0,1,0,0 1,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,-0.00609756097560976,0,1,1,0 0,0,0,0.6,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.236641221374046,0,1,1,0 1,0,1,3,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0.13986013986014,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.0335195530726257,0,1,1,0 1,0,1,2,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0.269230769230769,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.0632183908045978,0,1,0,0 1,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,-0.0124223602484472,0,1,1,1 1,0,0,4.4,3,1,0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,0.157142857142857,0,1,1,0 1,1,1,2.8,2,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0.10958904109589,0,1,1,0 0,0,0,0.4,0,1,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0.125,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,0.00613496932515334,0,1,1,0 0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-0.0295857988165681,0,1,1,0 1,0,0,0.8,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0.02,0,1,1,1 0,0,0,1.2,0,0,1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,-0.00602409638554213,0,1,1,0 1,0,1,2.8,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0.222222222222222,0,1,0,0 1,0,1,4,2,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,0.0902777777777777,0,1,1,1 1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.154411764705882,0,1,1,1 0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,-0.0164835164835165,0,1,0,0 1,1,0,1,2,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0.788888888888889,0,1,1,0 1,0,1,0.2,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0.32520325203252,0,1,1,0 1,0,0,1.2,0,1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0.325757575757576,0,1,1,0 1,1,0,3.4,2,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0.0780141843971631,0,1,1,1 1,0,1,1.2,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0.417391304347826,0,1,1,0 1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,-0.0632183908045977,0,1,1,0 0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0.0520231213872833,0,1,0,0 -------------------------------------------------------------------------------- /data/mammo_processed.csv: -------------------------------------------------------------------------------- 1 | "Malignant","RoundShape","OvalShape","LobularShape","IrregularShape","CircumscribedMargin","MicrolobulatedMargin","ObscuredMargin","IllDefinedMargin","SpiculatedMargin","Density","Age_lt_30","Age_geq_30","Age_geq_45","Age_geq_60" 1,0,0,1,0,0,0,0,0,1,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,1,0,0,0,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,0,0,0,1,0,3,0,1,0,0 1,1,0,0,0,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,1,0,1,1,1 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,2,0,1,0,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,1,0,1,1,1 1,0,0,0,1,0,0,1,0,0,1,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,2,0,1,1,1 0,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,0,0,0,0,1,2,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,2,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,2,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,1,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 1,0,0,1,0,0,0,0,0,1,2,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,0,0,1,1,0,0,0,0,4,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 1,0,0,1,0,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,2,0,1,0,0 0,0,1,0,0,1,0,0,0,0,1,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,1,0,0,0,1,0,0,0,0,2,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,2,0,1,1,1 0,0,1,0,0,0,0,0,1,0,1,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,2,0,1,0,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,1,0,1,1,0 1,0,0,0,1,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,0,0,0,0,1,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,2,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,0,0,0,1,0,0,1,0,0,2,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,4,0,1,1,0 1,0,0,0,1,0,0,0,1,0,4,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,2,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,1,0,1,0,0,0,0,3,1,0,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,1,0,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,2,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,4,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,2,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,1,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,1,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,0,0,0,1,0,0,1,0,0,1,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,1,0,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,1,0,0,0,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,1,0,0,2,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,1,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,1,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,2,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,1,0,0,0,2,0,1,0,0 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,1,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,4,0,1,1,0 0,0,0,1,0,0,0,0,1,0,4,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,2,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,2,0,1,0,0 0,1,0,0,0,1,0,0,0,0,2,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,0,0 0,1,0,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,1,0,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,1,0,0,0,0,1,0,0,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,0,0,1,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,1,0,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,4,0,1,1,0 0,1,0,0,0,0,0,1,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,4,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,1 0,0,0,0,1,0,1,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,1,0,0,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,0,0,1,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,1,0,0,0,0,0,0,0,1,3,0,1,1,1 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,1,0,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,1,0,1,0,0,0,0,3,1,0,0,0 1,0,0,1,0,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,0,0,1,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,1,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,0,1,0,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,0,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,1,0,1,0,0,0,0,4,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,1,0,0,1,0,0,0,3,0,1,1,1 0,0,1,0,0,0,1,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,1,0,0,0,1,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,1,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,1,0,0,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,1,0,0,4,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,1,0,0,0,0,0,0,0,1,3,0,1,1,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,0,0,1,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,0,1,0,0,0,1,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,0,0,0,1,1,0,0,0,0,1,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,1,0,0,0,0,1,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,1,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,1,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,1,0,0,0,0,1,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,1,0,0,0,0,0,0,1,0,3,0,1,0,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,2,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,2,0,1,1,1 0,0,1,0,0,0,0,0,1,0,2,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,4,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 0,0,0,1,0,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,1,0,0,2,0,1,0,0 0,0,0,1,0,0,0,0,1,0,2,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,2,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,2,0,1,0,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,1,0,0,1,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,4,0,1,1,0 0,0,0,1,0,0,1,0,0,0,3,0,1,1,1 0,1,0,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,0,1,0,1,0,0,0,0,2,0,1,0,0 0,0,0,1,0,1,0,0,0,0,2,0,1,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,1,0,1,1,1 1,0,0,0,1,0,0,1,0,0,4,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,2,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,2,0,1,1,1 0,0,1,0,0,0,1,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,1,0,1,0,0,0,0,3,1,0,0,0 1,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,2,0,1,0,0 1,0,0,1,0,1,0,0,0,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,1,0,0,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,1,0,0,0,2,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,0,0 0,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,1,0,0,1,0,0,0,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,0,0 1,0,1,0,0,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 1,0,0,1,0,0,0,1,0,0,2,0,1,0,0 1,0,0,1,0,0,1,0,0,0,3,0,1,1,1 1,1,0,0,0,1,0,0,0,0,1,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,1 1,0,0,1,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 1,0,0,1,0,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,1,0,3,0,1,1,0 1,0,0,1,0,1,0,0,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,1,0,3,0,1,0,0 0,0,1,0,0,0,0,0,1,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,0,1,0,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,1,0,0,1,0,0,0,3,0,1,0,0 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,1,0,0,0 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,0,1,0,0,1,0,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,2,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,0 1,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,1 0,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,1,0,0,0,1,0,0,0,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,1,0,0,3,0,1,1,0 1,0,0,1,0,0,0,0,1,0,3,0,1,1,0 0,1,0,0,0,1,0,0,0,0,1,0,1,1,1 1,1,0,0,0,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,1,0,3,0,1,1,1 0,0,1,0,0,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,0,0 1,0,0,0,1,0,0,0,1,0,3,0,1,1,0 0,0,1,0,0,1,0,0,0,0,3,0,1,1,0 1,0,0,0,1,0,0,0,0,1,3,0,1,1,0 0,0,0,0,1,0,0,0,0,1,3,0,1,1,1 1,0,0,0,1,0,0,0,0,1,3,0,1,1,1 0,0,0,1,0,0,0,1,0,0,3,0,1,1,1 -------------------------------------------------------------------------------- /demos/ex_1_basic_functionality.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import pandas as pd 4 | import cplex as cp 5 | import slim_python as slim 6 | 7 | #### LOAD DATA #### 8 | # requirements for CSV data file 9 | # - outcome variable in first column 10 | # - outcome variable values should be [-1, 1] or [0, 1] 11 | # - first row contains names for the outcome variable + input variables 12 | # - no empty cells 13 | data_name = 'breastcancer' 14 | data_dir = os.getcwd() + '/data/' 15 | data_csv_file = data_dir + data_name + '_processed.csv' 16 | 17 | # load data file from csv 18 | df = pd.read_csv(data_csv_file, sep = ',') 19 | data = df.as_matrix() 20 | data_headers = list(df.columns.values) 21 | N = data.shape[0] 22 | 23 | # setup Y vector and Y_name 24 | Y_col_idx = [0] 25 | Y = data[:, Y_col_idx] 26 | Y_name = [data_headers[j] for j in Y_col_idx] 27 | Y[Y == 0] = -1 28 | 29 | # setup X and X_names 30 | X_col_idx = [j for j in range(data.shape[1]) if j not in Y_col_idx] 31 | X = data[:, X_col_idx] 32 | X_names = [data_headers[j] for j in X_col_idx] 33 | 34 | # insert a column of ones to X for the intercept 35 | X = np.insert(arr = X, obj = 0, values = np.ones(N), axis = 1) 36 | X_names.insert(0, '(Intercept)') 37 | 38 | # run sanity checks 39 | slim.check_data(X = X, Y = Y, X_names = X_names) 40 | 41 | #### TRAIN SCORING SYSTEM USING SLIM #### 42 | # setup SLIM coefficient set 43 | coef_constraints = slim.SLIMCoefficientConstraints(variable_names = X_names, ub = 5, lb = -5) 44 | coef_constraints.view() 45 | 46 | #choose upper and lower bounds for the intercept coefficient 47 | #to ensure that there will be no regularization due to the intercept, choose 48 | # 49 | #intercept_ub < min_i(min_score_i) 50 | #intercept_lb > max_i(max_score_i) 51 | # 52 | #where min_score_i = min((Y*X) * \rho) for rho in \Lset 53 | #where max_score_i = max((Y*X) * \rho) for rho in \Lset 54 | # 55 | #setting intercept_ub and intercept_lb in this way ensures that we can always 56 | # classify every point as positive and negative 57 | scores_at_ub = (Y * X) * coef_constraints.ub 58 | scores_at_lb = (Y * X) * coef_constraints.lb 59 | non_intercept_ind = np.array([n != '(Intercept)' for n in X_names]) 60 | scores_at_ub = scores_at_ub[:, non_intercept_ind] 61 | scores_at_lb = scores_at_lb[:, non_intercept_ind] 62 | max_scores = np.fmax(scores_at_ub, scores_at_lb) 63 | min_scores = np.fmin(scores_at_ub, scores_at_lb) 64 | max_scores = np.sum(max_scores, 1) 65 | min_scores = np.sum(min_scores, 1) 66 | 67 | intercept_ub = -min(min_scores) + 1 68 | intercept_lb = -max(max_scores) + 1 69 | coef_constraints.set_field('ub', '(Intercept)', intercept_ub) 70 | coef_constraints.set_field('lb', '(Intercept)', intercept_lb) 71 | coef_constraints.view() 72 | 73 | 74 | #create SLIM IP 75 | slim_input = { 76 | 'X': X, 77 | 'X_names': X_names, 78 | 'Y': Y, 79 | 'C_0': 0.01, 80 | 'w_pos': 1.0, 81 | 'w_neg': 1.0, 82 | 'L0_min': 0, 83 | 'L0_max': float('inf'), 84 | 'err_min': 0, 85 | 'err_max': 1.0, 86 | 'pos_err_min': 0, 87 | 'pos_err_max': 1.0, 88 | 'neg_err_min': 0, 89 | 'neg_err_max': 1.0, 90 | 'coef_constraints': coef_constraints 91 | } 92 | 93 | slim_IP, slim_info = slim.create_slim_IP(slim_input) 94 | 95 | # setup SLIM IP parameters 96 | # see docs/usrccplex.pdf for more about these parameters 97 | slim_IP.parameters.timelimit.set(10.0) #set runtime here 98 | #TODO: add these default settings to create_slim_IP 99 | slim_IP.parameters.randomseed.set(0) 100 | slim_IP.parameters.threads.set(1) 101 | slim_IP.parameters.parallel.set(1) 102 | slim_IP.parameters.output.clonelog.set(0) 103 | slim_IP.parameters.mip.tolerances.mipgap.set(np.finfo(np.float).eps) 104 | slim_IP.parameters.mip.tolerances.absmipgap.set(np.finfo(np.float).eps) 105 | slim_IP.parameters.mip.tolerances.integrality.set(np.finfo(np.float).eps) 106 | slim_IP.parameters.emphasis.mip.set(1) 107 | 108 | 109 | # solve SLIM IP 110 | slim_IP.solve() 111 | 112 | # run quick and dirty tests to make sure that IP output is correct 113 | slim.check_slim_IP_output(slim_IP, slim_info, X, Y, coef_constraints) 114 | 115 | #### CHECK RESULTS #### 116 | slim_results = slim.get_slim_summary(slim_IP, slim_info, X, Y) 117 | pprint(slim_results) 118 | 119 | # print model 120 | print(slim_results['string_model']) 121 | 122 | # print coefficient vector 123 | print(slim_results['rho']) 124 | 125 | # print accuracy metrics 126 | print 'error_rate: %1.2f%%' % (100*slim_results['error_rate']) 127 | print 'TPR: %1.2f%%' % (100*slim_results['true_positive_rate']) 128 | print 'FPR: %1.2f%%' % (100*slim_results['false_positive_rate']) 129 | print 'true_positives: %d' % slim_results['true_positives'] 130 | print 'false_positives: %d' % slim_results['false_positives'] 131 | print 'true_negatives: %d' % slim_results['true_negatives'] 132 | print 'false_negatives: %d' % slim_results['false_negatives'] 133 | 134 | -------------------------------------------------------------------------------- /docs/usrcplex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustunb/slim-python/204c7db64cad0b139e748b299fea672bca9bc81e/docs/usrcplex.pdf -------------------------------------------------------------------------------- /images/slim_mushroom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustunb/slim-python/204c7db64cad0b139e748b299fea672bca9bc81e/images/slim_mushroom.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | pandas 4 | cplex 5 | PrettyTable -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | try: 3 | from setuptools import setup, Extension 4 | except ImportError: 5 | from distutils.core import setup, Extension 6 | 7 | setup(name='slim_python', 8 | version='1.0', 9 | description='learn optimized scoring systems from data', 10 | long_description = ''' 11 | slim-python is a free software package to train SLIM scoring systems 12 | using IBM ILOG CPLEX API and the Python programming language. ''', 13 | author='Berk Ustun', 14 | author_email='ustunb@mit.edu', 15 | url='https://www.berkustun.com/', 16 | packages=['slim_python'], 17 | ) -------------------------------------------------------------------------------- /slim_python/SLIMCoefficientConstraints.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from prettytable import PrettyTable 3 | 4 | 5 | class SLIMCoefficientConstraints(object): 6 | 7 | def check_string_input(self, input_name, input_value): 8 | if type(input_value) is np.array: 9 | 10 | if input_value.size == self.P: 11 | setattr(self, input_name, input_value) 12 | elif input_value.size == 1: 13 | setattr(self, input_name, np.repeat(input_value, self.P)) 14 | else: 15 | raise ValueError("length of %s is %d; should be %d" % (input_name, input_value.size, self.P)) 16 | 17 | elif type(input_value) is str: 18 | setattr(self, input_name, float(input_value)*np.ones(self.P)) 19 | 20 | elif type(input_value) is list: 21 | if len(input_value) == self.P: 22 | setattr(self, input_name, np.array([str(x) for x in input_value])) 23 | elif len(input_value) == 1: 24 | setattr(self, input_name, np.repeat(input_value, self.P)) 25 | else: 26 | raise ValueError("length of %s is %d; should be %d" % (input_name, len(input_value), self.P)) 27 | 28 | else: 29 | raise ValueError("user provided %s with an unsupported type" % input_name) 30 | 31 | def check_numeric_input(self, input_name, input_value): 32 | if type(input_value) is np.ndarray: 33 | 34 | if input_value.size == self.P: 35 | setattr(self, input_name, input_value) 36 | elif input_value.size == 1: 37 | setattr(self, input_name, input_value*np.ones(self.P)) 38 | else: 39 | raise ValueError("length of %s is %d; should be %d" % (input_name, input_value.size, self.P)) 40 | 41 | elif type(input_value) is float or type(input_value) is int: 42 | setattr(self, input_name, float(input_value)*np.ones(self.P)) 43 | 44 | elif type(input_value) is list: 45 | if len(input_value) == self.P: 46 | setattr(self, input_name, np.array([float(x) for x in input_value])) 47 | elif len(input_value) == 1: 48 | setattr(self, input_name, np.array([float(x) for x in input_value]) * np.ones(self.P)) 49 | else: 50 | raise ValueError("length of %s is %d; should be %d" % (input_name, len(input_value), self.P)) 51 | 52 | else: 53 | raise ValueError("user provided %s with an unsupported type" % (input_name)) 54 | 55 | def __init__(self, **kwargs): 56 | if 'variable_names' in kwargs: 57 | variable_names = kwargs.get('variable_names') 58 | P = len(variable_names) 59 | elif 'P' in kwargs: 60 | P = kwargs.get('P') 61 | variable_names = ["x_" + str(i) for i in range(1, P+1)] 62 | else: 63 | raise ValueError("user needs to provide 'P' or 'variable_names'") 64 | 65 | self.P = P 66 | self.variable_names = variable_names 67 | self.fix_flag = kwargs.get('fix_flag', True) 68 | self.check_flag = kwargs.get('check_flag', True) 69 | self.print_flag = kwargs.get('print_flag', False) 70 | 71 | ub = kwargs.get('ub', 10.0 * np.ones(P)) 72 | lb = kwargs.get('lb', -10.0 * np.ones(P)) 73 | vtype = kwargs.get('type', ['I']*P) 74 | C_0j = kwargs.get('C0_j', np.nan*np.ones(P)) 75 | sign = kwargs.get('sign', np.nan*np.ones(P)) 76 | 77 | self.check_numeric_input('ub', ub) 78 | self.check_numeric_input('lb', lb) 79 | self.check_numeric_input('C_0j', C_0j) 80 | self.check_numeric_input('sign', sign) 81 | self.check_string_input('vtype', vtype) 82 | 83 | if self.check_flag: self.check_set() 84 | if self.print_flag: self.view() 85 | 86 | def __len__(self): 87 | return self.P 88 | 89 | def check_set(self): 90 | 91 | for i in range(0, len(self.variable_names)): 92 | 93 | if self.ub[i] < self.lb[i]: 94 | if self.print_flag: 95 | print "fixed issue: ub < lb for variable %s" % self.variable_names[i] 96 | ub = ub[i] 97 | lb = lb[i] 98 | self.ub[i] = lb 99 | self.lb[i] = ub 100 | 101 | if self.sign[i] > 0 and self.lb[i] < 0: 102 | self.lb[i] = 0.0 103 | 104 | if self.sign[i] < 0 and self.ub[i] > 0: 105 | self.ub[i] = 0.0 106 | 107 | if self.variable_names[i] in {'Intercept','(Intercept)', 'intercept', '(intercept)'}: 108 | if self.C_0j[i] > 0 or np.isnan(self.C_0j[i]): 109 | if self.print_flag: 110 | print "found intercept variable with penalty value of C_0j = %1.4f" % self.C_0j[i] 111 | if self.fix_flag: 112 | if self.print_flag: 113 | print "setting C_0j for intercept to 0.0 to ensure that intercept is not penalized" 114 | self.C_0j[i] = 0.0 115 | 116 | def get_field_as_nparray(self, field_name): 117 | return np.array(getattr(self, field_name)) 118 | 119 | def get_field_as_list(self, field_name): 120 | return np.array(getattr(self, field_name)).tolist() 121 | 122 | def set_field(self, field_name, variable_names, field_values): 123 | 124 | curr_values = getattr(self, field_name) 125 | 126 | if type(variable_names) is str: 127 | 128 | variable_names = [variable_names] 129 | if type(field_values) is list: 130 | if len(field_values) is 1: 131 | pass 132 | else: 133 | raise ValueError("user provided multiple values for single field") 134 | 135 | elif type(field_values) is np.ndarray: 136 | if len(field_values) is 1: 137 | pass 138 | else: 139 | raise ValueError("user provided multiple values for single field") 140 | field_values = field_values.to_list() 141 | 142 | else: 143 | field_values = [field_values] 144 | 145 | elif type(variable_names) is list: 146 | 147 | if type(field_values) is list: 148 | if len(field_values) != len(variable_names): 149 | raise ValueError("length of variable names and values do not match") 150 | 151 | elif type(field_values) is np.ndarray: 152 | if len(field_values) == len(variable_names): 153 | raise ValueError("length of variable names and values do not match") 154 | field_values = field_values.to_list() 155 | 156 | else: 157 | field_values = [field_values]*len(variable_names) 158 | 159 | for variable_name in variable_names: 160 | 161 | if variable_name in self.variable_names: 162 | user_ind = variable_names.index(variable_name) 163 | self_ind = self.variable_names.index(variable_name) 164 | curr_values[self_ind] = field_values[user_ind] 165 | else: 166 | if self.print_flag: 167 | print "warning: Lset object does not contain variable with name: %s" % variable_name 168 | 169 | if self.check_flag: self.check_set() 170 | if self.print_flag: self.view() 171 | 172 | def view(self): 173 | x = PrettyTable() 174 | x.align = "r" 175 | x.add_column("variable_name", self.variable_names) 176 | x.add_column("vtype", self.get_field_as_list('vtype')) 177 | x.add_column("sign", self.get_field_as_list('sign')) 178 | x.add_column("lb", self.get_field_as_list('lb')) 179 | x.add_column("ub", self.get_field_as_list('ub')) 180 | x.add_column("C_0j", self.get_field_as_list('C_0j')) 181 | print x -------------------------------------------------------------------------------- /slim_python/__init__.py: -------------------------------------------------------------------------------- 1 | from .SLIMCoefficientConstraints import SLIMCoefficientConstraints 2 | from .create_slim_IP import * 3 | from .helper_functions import * 4 | -------------------------------------------------------------------------------- /slim_python/create_slim_IP.py: -------------------------------------------------------------------------------- 1 | import cplex 2 | import numpy as np 3 | from math import ceil, floor 4 | from helper_functions import * 5 | from SLIMCoefficientConstraints import SLIMCoefficientConstraints 6 | 7 | def create_slim_IP(input, print_flag = False): 8 | """ 9 | :param input: dictionary with the following keys 10 | %Y N x 1 np.array of labels (-1 or 1 only) 11 | %X N x P np.matrix of feature values (should include a column of 1s to act as an intercept 12 | %X_names P x 1 list of strings with names of the feature values (all unique and Intercept name) 13 | 14 | :return: 15 | %slim_IP 16 | %slim_info 17 | """ 18 | 19 | #setup printing 20 | if print_flag: 21 | def print_handle(msg): 22 | print_log(msg) 23 | else: 24 | def print_handle(msg): 25 | pass 26 | 27 | #check preconditions 28 | assert 'X' in input, 'no field named X in input' 29 | assert 'X_names' in input, 'no field named X_names in input' 30 | assert 'Y' in input, 'no field named Y in input' 31 | assert input['X'].shape[0] == input['Y'].shape[0] 32 | assert input['X'].shape[1] == len(input['X_names']) 33 | assert all((input['Y'] == 1) | (input['Y'] == -1)) 34 | 35 | XY = input['X'] * input['Y'] 36 | 37 | #sizes 38 | N = input['X'].shape[0] 39 | P = input['X'].shape[1] 40 | pos_ind = np.flatnonzero(input['Y'] == 1) 41 | neg_ind = np.flatnonzero(input['Y'] == -1) 42 | N_pos = len(pos_ind) 43 | N_neg = len(neg_ind) 44 | binary_data_flag = np.all((input['X'] == 0) | (input['X'] == 1)) 45 | 46 | #outcome variable name 47 | if ('Y_name' in input) and (type(input['Y_name']) is list): 48 | input['Y_name'] = input['Y_name'][0] 49 | elif ('Y_name' in input) and (type(input['Y_name']) is str): 50 | pass 51 | else: 52 | input['Y_name'] = 'Outcome' 53 | 54 | #TODO: check intercept conditions 55 | ## first column of X should be all 1s 56 | ## first element of X_name should be '(Intercept)' 57 | 58 | #set default parameters 59 | input = get_or_set_default(input, 'C_0', 0.01, print_flag = print_flag) 60 | input = get_or_set_default(input, 'w_pos', 1.0, print_flag = print_flag) 61 | input = get_or_set_default(input, 'w_neg', 2.0 - input['w_pos'], print_flag = print_flag) 62 | input = get_or_set_default(input, 'L0_min', 0, print_flag = print_flag) 63 | input = get_or_set_default(input, 'L0_max', P, print_flag = print_flag) 64 | input = get_or_set_default(input, 'err_min', 0.00, print_flag = print_flag) 65 | input = get_or_set_default(input, 'err_max', 1.00, print_flag = print_flag) 66 | input = get_or_set_default(input, 'pos_err_min', 0.00, print_flag = print_flag) 67 | input = get_or_set_default(input, 'pos_err_max', 1.00, print_flag = print_flag) 68 | input = get_or_set_default(input, 'neg_err_min', 0.00, print_flag = print_flag) 69 | input = get_or_set_default(input, 'neg_err_max', 1.00, print_flag = print_flag) 70 | 71 | #internal parameters 72 | input = get_or_set_default(input, 'C_1', float('nan'), print_flag = print_flag) 73 | input = get_or_set_default(input, 'M', float('nan'), print_flag = print_flag) 74 | input = get_or_set_default(input, 'epsilon', 0.001, print_flag = print_flag) 75 | 76 | #coefficient constraints 77 | if 'coef_constraints' in input: 78 | coef_constraints = input['coef_constraints'] 79 | else: 80 | coef_constraints = SLIMCoefficientConstraints(variable_names = input['X_names']) 81 | 82 | 83 | assert len(coef_constraints) == P 84 | 85 | # bounds 86 | rho_lb = np.array(coef_constraints.lb) 87 | rho_ub = np.array(coef_constraints.ub) 88 | rho_max = np.maximum(np.abs(rho_lb), np.abs(rho_ub)) 89 | beta_ub = rho_max 90 | beta_lb = np.zeros_like(rho_max) 91 | beta_lb[rho_lb > 0] = rho_lb[rho_lb > 0] 92 | beta_lb[rho_ub < 0] = rho_ub[rho_ub < 0] 93 | 94 | # signs 95 | signs = coef_constraints.sign 96 | sign_pos = signs == 1 97 | sign_neg = signs == -1 98 | 99 | #types 100 | types = coef_constraints.get_field_as_list('vtype') 101 | rho_type = ''.join(types) 102 | #TODO: add support for custom variable types 103 | 104 | #class-based weights 105 | w_pos = input['w_pos'] 106 | w_neg = input['w_neg'] 107 | w_total = w_pos + w_neg 108 | w_pos = 2.0 * (w_pos/w_total) 109 | w_neg = 2.0 * (w_neg/w_total) 110 | assert w_pos > 0.0 111 | assert w_neg > 0.0 112 | assert w_pos + w_neg == 2.0 113 | 114 | #L0 regularization penalty 115 | C_0j = np.copy(coef_constraints.C_0j) 116 | L0_reg_ind = np.isnan(C_0j) 117 | C_0j[L0_reg_ind] = input['C_0'] 118 | C_0 = C_0j 119 | assert(all(C_0[L0_reg_ind] > 0.0)) 120 | 121 | #L1 regularization penalty 122 | L1_reg_ind = L0_reg_ind 123 | if not np.isnan(input['C_1']): 124 | C_1 = input['C_1'] 125 | else: 126 | C_1 = 0.5 * min(w_pos/N, w_neg/N, min(C_0[L1_reg_ind] / np.sum(rho_max))) 127 | C_1 = C_1 * np.ones(shape = (P,)) 128 | C_1[~L1_reg_ind] = 0.0 129 | assert(all(C_1[L1_reg_ind] > 0.0)) 130 | 131 | # model size bounds 132 | L0_min = max(input['L0_min'], 0.0) 133 | L0_max = min(input['L0_max'], np.sum(L0_reg_ind)) 134 | L0_min = ceil(L0_min) 135 | L0_max = floor(L0_max) 136 | assert(L0_min <= L0_max) 137 | 138 | # total positive error bounds 139 | pos_err_min = 0.0 if np.isnan(input['pos_err_min']) else input['pos_err_min'] 140 | pos_err_max = 1.0 if np.isnan(input['pos_err_max']) else input['pos_err_max'] 141 | pos_err_min = max(ceil(N_pos*pos_err_min), 0) 142 | pos_err_max = min(floor(N_pos*pos_err_max), N_pos) 143 | 144 | # total negative error bounds 145 | neg_err_min = 0.0 if np.isnan(input['neg_err_min']) else input['neg_err_min'] 146 | neg_err_max = 1.0 if np.isnan(input['neg_err_max']) else input['neg_err_max'] 147 | neg_err_min = max(ceil(N_neg*neg_err_min), 0) 148 | neg_err_max = min(floor(N_neg*neg_err_max), N_neg) 149 | 150 | # total error bounds 151 | err_min = 0.0 if np.isnan(input['err_min']) else input['err_min'] 152 | err_max = 1.0 if np.isnan(input['err_max']) else input['err_max'] 153 | err_min = max(ceil(N*err_min), 0) 154 | err_max = min(floor(N*err_max), N) 155 | 156 | # sanity checks for error bounds 157 | assert(err_min <= err_max) 158 | assert(pos_err_min <= pos_err_max) 159 | assert(neg_err_min <= neg_err_max) 160 | assert(err_min >= 0) 161 | assert(pos_err_min >= 0) 162 | assert(neg_err_min >= 0) 163 | assert(err_max <= N) 164 | assert(pos_err_max <= N_pos) 165 | assert(neg_err_max <= N_neg) 166 | 167 | #TODO: strengthen bounds 168 | #loss constraint parameters 169 | epsilon = input['epsilon'] 170 | if np.isnan(input['M']): 171 | max_points = np.maximum(XY * rho_lb, XY * rho_ub) 172 | max_score_reg = np.sum(-np.sort(-max_points[:, L0_reg_ind])[:, 0:int(L0_max)], axis = 1) 173 | max_score_no_reg = np.sum(max_points[:, ~L0_reg_ind], axis = 1) 174 | max_score = max_score_reg + max_score_no_reg 175 | M = max_score + 1.05 * epsilon 176 | else: 177 | M = input['M'] 178 | 179 | #sanity checks for loss constraint parameters 180 | M = M * np.ones(shape = (N,)) 181 | M_max = max(np.sum(abs(XY) * rho_max, axis = 1)) + 1.05 * input['epsilon'] 182 | assert(len(M) == N) 183 | assert(all(M > 0)) 184 | assert(all(M <= M_max)) 185 | assert(epsilon > 0.0) 186 | assert(epsilon < 1.0) 187 | 188 | 189 | #### CREATE CPLEX IP 190 | 191 | #TODO: describe IP 192 | 193 | # x = [loss_pos, loss_neg, rho_j, alpha_j] 194 | 195 | #optional constraints: 196 | # objval = w_pos * loss_pos + w_neg * loss_min + sum(C_0j * alpha_j) (required for callback) 197 | # L0_norm = sum(alpha_j) (required for callback) 198 | 199 | #rho = P x 1 vector of coefficient values 200 | #alpha = P x 1 vector of L0-norm variables, alpha(j) = 1 if lambda_j != 0 201 | #beta = P x 1 vector of L1-norm variables, beta(j) = abs(lambda_j) 202 | #error = N x 1 vector of loss variables, error(i) = 1 if error on X(i) 203 | #pos_err = auxiliary variable := sum(error[i]) for i: y_i = +1 204 | #neg_err = auxiliary variable := sum(error[i]) for i: y_i = +1 205 | #l0_norm = auxiliary variable := L0_norm = sum(alpha[j]) 206 | 207 | ## IP VARIABLES 208 | 209 | #objective costs (we solve min total_error + N * C_0 * L0_norm + N 210 | err_cost = np.ones(shape = (N,)) 211 | err_cost[pos_ind] = w_pos 212 | err_cost[neg_ind] = w_neg 213 | C_0 = N * C_0 214 | C_1 = N * C_1 215 | 216 | #variable-related values 217 | obj = [0.0] * P + C_0.tolist() + C_1.tolist() + err_cost.tolist() 218 | ub = rho_ub.tolist() + [1] * P + beta_ub.tolist() + [1] * N 219 | lb = rho_lb.tolist() + [0] * P + beta_lb.tolist() + [0] * N 220 | ctype = rho_type + 'B'*P + 'C'*P + 'B'*N 221 | 222 | #variable-related names 223 | rho_names = ['rho_' + str(j) for j in range(0, P)] 224 | alpha_names = ['alpha_' + str(j) for j in range(0, P)] 225 | beta_names = ['beta_' + str(j) for j in range(0, P)] 226 | error_names = ['error_' + str(i) for i in range(0, N)] 227 | var_names = rho_names + alpha_names + beta_names + error_names 228 | 229 | #variable-related error checking 230 | n_var = 3 * P + N 231 | assert(len(obj) == n_var) 232 | assert(len(ub) == n_var) 233 | assert(len(lb) == n_var) 234 | assert(len(ctype) == n_var) 235 | assert(len(var_names) == n_var) 236 | 237 | #add variables 238 | slim_IP = cplex.Cplex() 239 | slim_IP.objective.set_sense(slim_IP.objective.sense.minimize) 240 | slim_IP.variables.add(obj = obj, lb = lb, ub = ub, types = ctype, names=var_names) 241 | 242 | #Loss Constraints 243 | #Enforce z_i = 1 if incorrect classification) 244 | #M_i * z_i >= XY[i,].dot(rho) + epsilon 245 | for i in range(0, N): 246 | slim_IP.linear_constraints.add(names = ["error_" + str(i)], 247 | lin_expr = [cplex.SparsePair(ind = rho_names + [error_names[i]], 248 | val = XY[i,].tolist() + [M[i]])], 249 | senses = "G", 250 | rhs = [epsilon]) 251 | 252 | # 0-Norm LB Constraints: 253 | # lambda_j,lb * alpha_j <= lambda_j <= Inf 254 | # 0 <= lambda_j - lambda_j,lb * alpha_j < Inf 255 | for j in range(0, P): 256 | slim_IP.linear_constraints.add(names = ["L0_norm_lb_" + str(j)], 257 | lin_expr = [cplex.SparsePair(ind = [rho_names[j], alpha_names[j]], 258 | val = [1.0, -rho_lb[j]])], 259 | senses = "G", 260 | rhs = [0.0]) 261 | 262 | # 0-Norm UB Constraints: 263 | # lambda_j <= lambda_j,ub * alpha_j 264 | # 0 <= -lambda_j + lambda_j,ub * alpha_j 265 | for j in range(0, P): 266 | slim_IP.linear_constraints.add(names = ["L0_norm_ub_" + str(j)], 267 | lin_expr = [cplex.SparsePair(ind = [rho_names[j], alpha_names[j]], 268 | val = [-1.0, rho_ub[j]])], 269 | senses = "G", 270 | rhs = [0.0]) 271 | 272 | 273 | # 1-Norm Positive Constraints: 274 | #actual constraint: lambda_j <= beta_j 275 | #cplex constraint: 0 <= -lambda_j + beta_j <= Inf 276 | for j in range(0, P): 277 | slim_IP.linear_constraints.add(names = ["L1_norm_pos_" + str(j)], 278 | lin_expr = [cplex.SparsePair(ind = [rho_names[j], beta_names[j]], 279 | val = [-1.0, 1.0])], 280 | senses = "G", 281 | rhs = [0.0]) 282 | 283 | 284 | # 1-Norm Negative Constraints: 285 | #actual constraint: -lambda_j <= beta_j 286 | #cplex constraint: 0 <= lambda_j + beta_j <= Inf 287 | for j in range(0, P): 288 | slim_IP.linear_constraints.add(names = ["L1_norm_neg_" + str(j)], 289 | lin_expr = [cplex.SparsePair(ind = [rho_names[j], beta_names[j]], 290 | val = [1.0, 1.0])], 291 | senses = "G", 292 | rhs = [0.0]) 293 | 294 | # flags for whether or not we will add contraints 295 | add_L0_norm_constraint = (L0_min > 0) or (L0_max < P) 296 | add_total_error_constraint = (err_min > 0) or (err_max < N) 297 | add_pos_error_constraint = (pos_err_min > 0) or (pos_err_max < N_pos) or (add_total_error_constraint) 298 | add_neg_error_constraint = (neg_err_min > 0) or (neg_err_max < N_neg) or (add_total_error_constraint) 299 | 300 | ### auxiliary variables and bounds 301 | total_l0_norm_name = ['total_l0_norm'] 302 | total_error_name = ['total_error'] 303 | total_error_pos_name = ['total_error_pos_name'] 304 | total_error_neg_name = ['total_error_neg_name'] 305 | 306 | slim_IP.variables.add(names = total_l0_norm_name, 307 | obj = [0.0], 308 | lb = [L0_min], 309 | ub = [L0_max], 310 | types = 'I') 311 | 312 | slim_IP.variables.add(names = total_error_name, 313 | obj = [0.0], 314 | lb = [err_min], 315 | ub = [err_max], 316 | types = 'I') 317 | 318 | slim_IP.variables.add(names = total_error_pos_name, 319 | obj = [0.0], 320 | lb = [pos_err_min], 321 | ub = [pos_err_max], 322 | types = 'I') 323 | 324 | slim_IP.variables.add(names = total_error_neg_name, 325 | obj = [0.0], 326 | lb = [neg_err_min], 327 | ub = [neg_err_max], 328 | types = 'I') 329 | 330 | 331 | # L0_norm constraint 332 | #if add_L0_norm_constraint: 333 | slim_IP.linear_constraints.add(names = ["total_L0_norm"], 334 | lin_expr = [cplex.SparsePair(ind = alpha_names + total_l0_norm_name, 335 | val = [-1.0] * P + [1.0])], 336 | senses = "E", 337 | rhs = [0.0]) 338 | 339 | # total_pos_error variable definition constraint 340 | #err_pos = sum(error[i]) for i in pos_ind 341 | #if add_pos_error_constraint: 342 | slim_IP.linear_constraints.add(names = ["total_pos_error"], 343 | lin_expr = [cplex.SparsePair(ind = [error_names[i] for i in pos_ind] + total_error_pos_name, 344 | val = [-1.0] * N_pos + [1.0])], 345 | senses = "E", 346 | rhs = [0.0]) 347 | 348 | 349 | # total_neg_error variable definition constraint 350 | #err_neg = sum(error[i]) for i in neg_ind 351 | #if add_neg_error_constraint: 352 | slim_IP.linear_constraints.add(names = ["total_neg_error"], 353 | lin_expr = [cplex.SparsePair(ind = [error_names[i] for i in neg_ind] + total_error_neg_name, 354 | val = [-1.0] * N_neg + [1.0])], 355 | senses = "E", 356 | rhs = [0.0]) 357 | 358 | # total_error variable definition constraint 359 | #if add_total_error_constraint: 360 | slim_IP.linear_constraints.add(names = ["total_error"], 361 | lin_expr = [cplex.SparsePair(ind = total_error_name + total_error_pos_name + total_error_neg_name, 362 | val = [1.0, -1.0, -1.0])], 363 | senses = "E", 364 | rhs = [0.0]) 365 | 366 | 367 | #### Drop Variables and Constraints 368 | variables_to_drop = [] 369 | constraints_to_drop = [] 370 | 371 | # drop alpha[j] and beta[j] if L0_reg_ind == False 372 | no_L0_reg_ind = np.flatnonzero(~L0_reg_ind).tolist() 373 | variables_to_drop += ["alpha_" + str(j) for j in no_L0_reg_ind] 374 | variables_to_drop += ["beta_" + str(j) for j in no_L0_reg_ind] 375 | constraints_to_drop += ["L0_norm_lb_" + str(j) for j in no_L0_reg_ind] 376 | constraints_to_drop += ["L0_norm_ub_" + str(j) for j in no_L0_reg_ind] 377 | constraints_to_drop += ["L1_norm_pos_" + str(j) for j in no_L0_reg_ind] 378 | constraints_to_drop += ["L1_norm_neg_" + str(j) for j in no_L0_reg_ind] 379 | 380 | # drop beta[j] if L0_reg_ind == False or L1_reg_ind == False 381 | no_L1_reg_ind = np.flatnonzero(~L1_reg_ind).tolist() 382 | variables_to_drop += ["beta_" + str(j) for j in no_L1_reg_ind] 383 | constraints_to_drop += ["L1_norm_pos_" + str(j) for j in no_L1_reg_ind] 384 | constraints_to_drop += ["L1_norm_neg_" + str(j) for j in no_L1_reg_ind] 385 | 386 | # drop alpha[j] and beta[j] if values are fixed at 0 387 | fixed_value_ind = np.flatnonzero(rho_lb == rho_ub).tolist() 388 | variables_to_drop += ["alpha_" + str(j) for j in fixed_value_ind] 389 | variables_to_drop += ["beta_" + str(j) for j in fixed_value_ind] 390 | constraints_to_drop += ["L0_norm_lb_" + str(j) for j in fixed_value_ind] 391 | constraints_to_drop += ["L0_norm_ub_" + str(j) for j in fixed_value_ind] 392 | constraints_to_drop += ["L1_norm_pos_" + str(j) for j in fixed_value_ind] 393 | constraints_to_drop += ["L1_norm_neg_" + str(j) for j in fixed_value_ind] 394 | 395 | # drop constraints based on signs 396 | sign_pos_ind = np.flatnonzero(sign_pos).tolist() 397 | sign_neg_ind = np.flatnonzero(sign_neg).tolist() 398 | 399 | # drop L1_norm_neg constraint for any variable rho[j] >= 0 400 | constraints_to_drop += ["L1_norm_neg_" + str(j) for j in sign_pos_ind] 401 | 402 | # drop L0_norm_lb constraint for any variable rho[j] >= 0 403 | constraints_to_drop += ["L0_norm_lb_" + str(j) for j in sign_pos_ind] 404 | 405 | # drop L1_norm_pos constraint for any variable rho[j] <= 0 406 | constraints_to_drop += ["L1_norm_pos_" + str(j) for j in sign_neg_ind] 407 | 408 | # drop L0_norm_ub constraint for any variable rho[j] <= 0 409 | constraints_to_drop += ["L0_norm_ub_" + str(j) for j in sign_neg_ind] 410 | 411 | if len(constraints_to_drop) > 0: 412 | constraints_to_drop = list(set(constraints_to_drop)) 413 | slim_IP.linear_constraints.delete(constraints_to_drop) 414 | 415 | if len(variables_to_drop) > 0: 416 | variables_to_drop = list(set(variables_to_drop)) 417 | slim_IP.variables.delete(variables_to_drop) 418 | 419 | #create info dictionary for debugging 420 | rho_names = [n for n in rho_names if n not in variables_to_drop] 421 | alpha_names = [n for n in alpha_names if n not in variables_to_drop] 422 | beta_names = [n for n in beta_names if n not in variables_to_drop] 423 | 424 | slim_info = { 425 | # 426 | # key parameters 427 | # 428 | "C_0": C_0, 429 | "C_1": C_1, 430 | "w_pos": w_pos, 431 | "w_neg": w_neg, 432 | "err_min": err_min, 433 | "err_max": err_max, 434 | "pos_err_min": pos_err_min, 435 | "pos_err_max": pos_err_max, 436 | "neg_err_min": neg_err_min, 437 | "neg_err_max": neg_err_max, 438 | "L0_min": L0_min, 439 | "L0_max": L0_max, 440 | "N": N, 441 | "P": P, 442 | "N_pos": N_pos, 443 | "N_neg": N_neg, 444 | "rho_ub": rho_ub, 445 | "rho_lb": rho_lb, 446 | "M": M, 447 | "epsilon": epsilon, 448 | # 449 | "binary_data_flag": binary_data_flag, 450 | "pos_ind": pos_ind, 451 | "neg_ind": neg_ind, 452 | "L0_reg_ind": L0_reg_ind, 453 | "L1_reg_ind": L1_reg_ind, 454 | # 455 | "n_variables": slim_IP.variables.get_num(), 456 | "n_constraints": slim_IP.linear_constraints.get_num(), 457 | "names": slim_IP.variables.get_names(), 458 | # 459 | # MIP variables indices 460 | # 461 | "rho_idx": slim_IP.variables.get_indices(rho_names), 462 | "alpha_idx": slim_IP.variables.get_indices(alpha_names), 463 | "beta_idx": slim_IP.variables.get_indices(beta_names), 464 | "error_idx": slim_IP.variables.get_indices(error_names), 465 | "total_l0_norm_idx": slim_IP.variables.get_indices(total_l0_norm_name), 466 | "total_error_idx": slim_IP.variables.get_indices(total_error_name), 467 | "total_error_pos_idx": slim_IP.variables.get_indices(total_error_pos_name), 468 | "total_error_neg_idx": slim_IP.variables.get_indices(total_error_neg_name), 469 | # 470 | # MIP variables names 471 | # 472 | "rho_names": rho_names, 473 | "alpha_names": alpha_names, 474 | "beta_names": beta_names, 475 | "rho_names": rho_names, 476 | "error_names": error_names, 477 | "total_error_name": total_error_name, 478 | "total_error_pos_name": total_error_pos_name, 479 | "total_error_neg_name": total_error_neg_name, 480 | # 481 | "X_names": input['X_names'], 482 | "Y_name": input['Y_name'], 483 | # 484 | # dropped 485 | "variables_to_drop": variables_to_drop, 486 | "constraints_to_drop": constraints_to_drop, 487 | } 488 | 489 | 490 | return slim_IP, slim_info 491 | -------------------------------------------------------------------------------- /slim_python/helper_functions.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | import numpy as np 5 | import cplex 6 | import warnings 7 | from prettytable import PrettyTable 8 | 9 | #PRINTING AND LOGGING 10 | def print_log(msg, print_flag = True): 11 | if print_flag: 12 | if type(msg) is str: 13 | print ('%s | ' % (time.strftime("%m/%d/%y @ %I:%M %p", time.localtime()))) + msg 14 | else: 15 | print '%s | %r' % (time.strftime("%m/%d/%y @ %I:%M %p", time.localtime()), msg) 16 | sys.stdout.flush() 17 | 18 | def get_rho_string(rho, vtypes = 'I'): 19 | if len(vtypes) == 1: 20 | if vtypes == 'I': 21 | rho_string = ' '.join(map(lambda x: str(int(x)), rho)) 22 | else: 23 | rho_string = ' '.join(map(lambda x: str(x), rho)) 24 | else: 25 | rho_string = '' 26 | for j in range(0, len(rho)): 27 | if vtypes[j] == 'I': 28 | rho_string += ' ' + str(int(rho[j])) 29 | else: 30 | rho_string += (' %1.6f' % rho[j]) 31 | 32 | return rho_string 33 | 34 | #LOADING SETTINGS FROM DISK 35 | def easy_type(data_value): 36 | type_name = type(data_value).__name__ 37 | if type_name in {"list", "set"}: 38 | types = {easy_type(item) for item in data_value} 39 | if len(types) == 1: 40 | return next(iter(types)) 41 | elif types.issubset({"int", "float"}): 42 | return "float" 43 | else: 44 | return "multiple" 45 | elif type_name == "str": 46 | if data_value in {'True', 'TRUE'}: 47 | return "bool" 48 | elif data_value in {'False', 'FALSE'}: 49 | return "bool" 50 | else: 51 | return "str" 52 | elif type_name == "int": 53 | return "int" 54 | elif type_name == "float": 55 | return "float" 56 | elif type_name == "bool": 57 | return "bool" 58 | else: 59 | return "unknown" 60 | 61 | def convert_str_to_bool(val): 62 | val = val.lower().strip() 63 | if val == 'true': 64 | return True 65 | elif val == 'false': 66 | return False 67 | else: 68 | return None 69 | 70 | def get_or_set_default(settings, setting_name, default_value, type_check = False, print_flag = False): 71 | 72 | if setting_name in settings: 73 | if type_check: 74 | #check type match 75 | default_type = type(default_value) 76 | user_type = type(settings[setting_name]) 77 | if user_type == default_type: 78 | settings[setting_name] = default_value 79 | else: 80 | print_log("type mismatch on %s: user provided type: %s and but expected type: %s" % (setting_name, user_type, default_type), print_flag) 81 | print_log("setting %s to its default value: %r" % (setting_name, default_value), print_flag) 82 | settings[setting_name] = default_value 83 | #else: do nothing 84 | else: 85 | print_log("setting %s to its default value: %r" % (setting_name, default_value), print_flag) 86 | settings[setting_name] = default_value 87 | 88 | return settings 89 | 90 | #PROCESSING 91 | def get_prediction(x, rho): 92 | return np.sign(x.dot(rho)) 93 | 94 | def get_true_positives_from_pred(yhat, pos_ind): 95 | return np.sum(yhat[pos_ind] == 1) 96 | 97 | def get_false_positives_from_pred(yhat, pos_ind): 98 | return np.sum(yhat[~pos_ind] == 1) 99 | 100 | def get_true_negatives_from_pred(yhat, pos_ind): 101 | return np.sum(yhat[~pos_ind] != 1) 102 | 103 | def get_false_negatives_from_pred(yhat, pos_ind): 104 | return np.sum(yhat[pos_ind] != 1) 105 | 106 | def get_accuracy_stats(model, data, error_checking = True): 107 | 108 | # old functions (inefficient) 109 | # get_true_positives = lambda x, y, rho: np.sum(get_prediction(x[y == 1], rho) == 1) 110 | # get_true_negatives = lambda x, y, rho: np.sum(get_prediction(x[y != 1], rho) != 1) 111 | # get_false_positives = lambda x, y, rho: np.sum(get_prediction(x[y != 1], rho) == 1) 112 | # get_false_negatives = lambda x, y, rho: np.sum(get_prediction(x[y == 1], rho) != 1) 113 | 114 | accuracy_stats = { 115 | 'train_true_positives': np.nan, 116 | 'train_true_negatives': np.nan, 117 | 'train_false_positives': np.nan, 118 | 'train_false_negatives': np.nan, 119 | 'valid_true_positives': np.nan, 120 | 'valid_true_negatives': np.nan, 121 | 'valid_false_positives': np.nan, 122 | 'valid_false_negatives': np.nan, 123 | 'test_true_positives': np.nan, 124 | 'test_true_negatives': np.nan, 125 | 'test_false_positives': np.nan, 126 | 'test_false_negatives': np.nan, 127 | } 128 | 129 | model = np.array(model).reshape(data['X'].shape[1], 1) 130 | 131 | # training set 132 | data_prefix = 'train' 133 | X_field_name = 'X' 134 | Y_field_name = 'Y' 135 | Yhat = get_prediction(data['X'], model) 136 | pos_ind = data[Y_field_name] == 1 137 | 138 | accuracy_stats[data_prefix + '_' + 'true_positives'] = get_true_positives_from_pred(Yhat, pos_ind) 139 | accuracy_stats[data_prefix + '_' + 'true_negatives'] = get_true_negatives_from_pred(Yhat, pos_ind) 140 | accuracy_stats[data_prefix + '_' + 'false_positives'] = get_false_positives_from_pred(Yhat, pos_ind) 141 | accuracy_stats[data_prefix + '_' + 'false_negatives'] = get_false_negatives_from_pred(Yhat, pos_ind) 142 | 143 | if error_checking: 144 | N_check = (accuracy_stats[data_prefix + '_' + 'true_positives'] + 145 | accuracy_stats[data_prefix + '_' + 'true_negatives'] + 146 | accuracy_stats[data_prefix + '_' + 'false_positives'] + 147 | accuracy_stats[data_prefix + '_' + 'false_negatives']) 148 | assert data[X_field_name].shape[0] == N_check 149 | 150 | # validation set 151 | data_prefix = 'valid' 152 | X_field_name = 'X' + '_' + data_prefix 153 | Y_field_name = 'Y' + '_' + data_prefix 154 | has_validation_set = (X_field_name in data and 155 | Y_field_name in data and 156 | data[X_field_name].shape[0] > 0 and 157 | data[Y_field_name].shape[0] > 0) 158 | 159 | if has_validation_set: 160 | 161 | Yhat = get_prediction(data[X_field_name], model) 162 | pos_ind = data[Y_field_name] == 1 163 | accuracy_stats[data_prefix + '_' + 'true_positives'] = get_true_positives_from_pred(Yhat, pos_ind) 164 | accuracy_stats[data_prefix + '_' + 'true_negatives'] = get_true_negatives_from_pred(Yhat, pos_ind) 165 | accuracy_stats[data_prefix + '_' + 'false_positives'] = get_false_positives_from_pred(Yhat, pos_ind) 166 | accuracy_stats[data_prefix + '_' + 'false_negatives'] = get_false_negatives_from_pred(Yhat, pos_ind) 167 | 168 | if error_checking: 169 | N_check = (accuracy_stats[data_prefix + '_' + 'true_positives'] + 170 | accuracy_stats[data_prefix + '_' + 'true_negatives'] + 171 | accuracy_stats[data_prefix + '_' + 'false_positives'] + 172 | accuracy_stats[data_prefix + '_' + 'false_negatives']) 173 | assert data[X_field_name].shape[0] == N_check 174 | 175 | # test set 176 | data_prefix = 'test' 177 | X_field_name = 'X' + '_' + data_prefix 178 | Y_field_name = 'Y' + '_' + data_prefix 179 | has_test_set = (X_field_name in data and 180 | Y_field_name in data and 181 | data[X_field_name].shape[0] > 0 and 182 | data[Y_field_name].shape[0] > 0) 183 | 184 | if has_test_set: 185 | 186 | Yhat = get_prediction(data[X_field_name], model) 187 | pos_ind = data[Y_field_name] == 1 188 | accuracy_stats[data_prefix + '_' + 'true_positives'] = get_true_positives_from_pred(Yhat, pos_ind) 189 | accuracy_stats[data_prefix + '_' + 'true_negatives'] = get_true_negatives_from_pred(Yhat, pos_ind) 190 | accuracy_stats[data_prefix + '_' + 'false_positives'] = get_false_positives_from_pred(Yhat, pos_ind) 191 | accuracy_stats[data_prefix + '_' + 'false_negatives'] = get_false_negatives_from_pred(Yhat, pos_ind) 192 | 193 | if error_checking: 194 | N_check = (accuracy_stats[data_prefix + '_' + 'true_positives'] + 195 | accuracy_stats[data_prefix + '_' + 'true_negatives'] + 196 | accuracy_stats[data_prefix + '_' + 'false_positives'] + 197 | accuracy_stats[data_prefix + '_' + 'false_negatives']) 198 | assert data[X_field_name].shape[0] == N_check 199 | 200 | return accuracy_stats 201 | 202 | #DATA CHECKING 203 | def check_data(X, X_names, Y): 204 | 205 | #type checks 206 | assert type(X) is np.ndarray, "type(X) should be numpy.ndarray" 207 | assert type(Y) is np.ndarray, "type(Y) should be numpy.ndarray" 208 | assert type(X_names) is list, "X_names should be a list" 209 | 210 | #sizes and uniqueness 211 | N, P = X.shape 212 | assert N > 0, 'X matrix must have at least 1 row' 213 | assert P > 0, 'X matrix must have at least 1 column' 214 | assert len(Y) == N, 'len(Y) should be same as # of rows in X' 215 | assert len(list(set(X_names))) == len(X_names), 'X_names is not unique' 216 | assert len(X_names) == P, 'len(X_names) should be same as # of cols in X' 217 | 218 | #X_matrix values 219 | if '(Intercept)' in X_names: 220 | assert all(X[:, X_names.index('(Intercept)')] == 1.0), "'(Intercept)' column should only be composed of 1s" 221 | else: 222 | warnings.warn("there is no column named '(Intercept)' in X_names") 223 | assert np.all(~np.isnan(X)), 'X has nan entries' 224 | assert np.all(~np.isinf(X)), 'X has inf entries' 225 | 226 | #Y vector values 227 | assert all((Y == 1)|(Y == -1)), 'Y[i] should = [-1,1] for all i' 228 | if all(Y == 1): 229 | warnings.warn("all Y_i == 1 for all i") 230 | if all(Y == -1): 231 | warnings.warn("all Y_i == -1 for all i") 232 | 233 | #TODO (optional) collect warnings and return those? 234 | 235 | def check_slim_IP_output(slim_IP, slim_info, X, Y, coef_constraints): 236 | 237 | #TODO skip tests if there is no solution 238 | #TODO return true to prove that it's passed tests 239 | #TODO (optional) collect warnings and return those? 240 | 241 | #MIP related sanity checks 242 | assert len(slim_IP.solution.get_values()) == slim_info['n_variables'] 243 | 244 | #setup function handles for convenient checking 245 | get_L0_norm = lambda x: np.sum(np.count_nonzero(x[slim_info['L0_reg_ind']])) 246 | 247 | #key variables 248 | rho = np.array(slim_IP.solution.get_values(slim_info['rho_idx'])) 249 | alpha = np.array(slim_IP.solution.get_values(slim_info['alpha_idx'])) 250 | beta = np.array(slim_IP.solution.get_values(slim_info['beta_idx'])) 251 | err = np.array(slim_IP.solution.get_values(slim_info['error_idx'])) 252 | 253 | #auxiliary variables 254 | total_error = np.array(slim_IP.solution.get_values(slim_info['total_error_idx'])) 255 | total_error_pos = np.array(slim_IP.solution.get_values(slim_info['total_error_pos_idx'])) 256 | total_error_neg = np.array(slim_IP.solution.get_values(slim_info['total_error_neg_idx'])) 257 | total_l0_norm = np.array(slim_IP.solution.get_values(slim_info['total_l0_norm_idx'])) 258 | 259 | # helper parameters 260 | L0_reg_ind = slim_info['L0_reg_ind'] 261 | L1_reg_ind = slim_info['L1_reg_ind'] 262 | rho_L0_reg = rho[L0_reg_ind] 263 | rho_L1_reg = rho[L1_reg_ind] 264 | beta_ub_reg = np.maximum(abs(coef_constraints.ub[L1_reg_ind]), coef_constraints.lb[L1_reg_ind]) 265 | beta_lb_reg = np.zeros_like(beta_ub_reg) 266 | beta_lb_reg = np.maximum(beta_lb_reg, slim_info['rho_lb'][L1_reg_ind]) 267 | beta_lb_reg = -np.minimum(beta_lb_reg, slim_info['rho_ub'][L1_reg_ind]) 268 | beta_lb_reg = abs(beta_lb_reg) 269 | 270 | # test on coefficient vector 271 | assert len(rho) == len(coef_constraints), 'rho has the wrong length' 272 | assert all(rho <= slim_info['rho_ub']), 'rho exceeds upper bounds' 273 | assert all(rho >= slim_info['rho_lb']), 'rho exceeds lower bounds' 274 | 275 | # tests on L0 indicator variables 276 | assert all((alpha == 0)|(alpha == 1)), 'alpha should be binary' 277 | assert all(abs(rho_L0_reg[alpha == 0]) == 0.0), 'alpha = 0 should => that rho == 0' 278 | assert all(abs(rho_L0_reg[alpha == 1]) > 0.0), 'alpha = 1 should => that rho != 0' 279 | 280 | # tests on L1 helper variables 281 | assert all(abs(rho_L1_reg) == beta), 'beta != abs(rho)' 282 | assert all(beta >= beta_lb_reg), 'beta should be <= beta_ub' 283 | assert all(beta <= beta_ub_reg), 'beta should be >= beta_lb' 284 | 285 | # L0-norm bounds 286 | expected_l0_norm = get_L0_norm(rho) 287 | assert sum(alpha) == expected_l0_norm, 'alpha should := 1[rho != 0]' 288 | assert total_l0_norm == expected_l0_norm 289 | assert sum(alpha) >= slim_info['L0_min'] 290 | assert sum(alpha) <= slim_info['L0_max'] 291 | assert total_l0_norm >= slim_info['L0_min'] 292 | assert total_l0_norm <= slim_info['L0_max'] 293 | assert expected_l0_norm >= slim_info['L0_min'] 294 | assert expected_l0_norm <= slim_info['L0_max'] 295 | 296 | # aggregate error measure tests 297 | expected_scores = (Y*X).dot(rho) 298 | expected_err_values = expected_scores <= slim_info['epsilon'] 299 | assert all((err == 0) | (err == 1)), 'err should be binary' 300 | assert all(err == expected_err_values), 'error vector is not == sign(XY.dot(rho) + epsilon)' 301 | assert total_error == sum(err), 'total_error should == sum(error(i))' 302 | assert total_error == total_error_pos + total_error_neg, 'total_error should == total_error_pos + total_error_neg' 303 | assert total_error_pos == sum(err[slim_info['pos_ind']]) 304 | assert total_error_neg == sum(err[slim_info['neg_ind']]) 305 | assert all(-expected_scores <= slim_info['M']), 'Big M is not big enough' 306 | 307 | # extra sanity check tests 308 | assert total_error <= min(slim_info['N_pos'], slim_info['N_neg']), 'total_error should be less than total_error_pos + total_error_neg' 309 | 310 | def print_slim_model(rho, X_names, Y_name, show_omitted_variables = False): 311 | 312 | rho_values = np.copy(rho) 313 | rho_names = list(X_names) 314 | 315 | if '(Intercept)' in rho_names: 316 | intercept_ind = X_names.index('(Intercept)') 317 | intercept_val = int(rho[intercept_ind]) 318 | rho_values = np.delete(rho_values, intercept_ind) 319 | rho_names.remove('(Intercept)' ) 320 | else: 321 | intercept_val = 0 322 | 323 | if Y_name is None: 324 | predict_string = "PREDICT Y = +1 IF SCORE >= %d" % intercept_val 325 | else: 326 | predict_string = "PREDICT %s IF SCORE >= %d" % (Y_name[0].upper(), intercept_val) 327 | 328 | if not show_omitted_variables: 329 | selected_ind = np.flatnonzero(rho_values) 330 | rho_values = rho_values[selected_ind] 331 | rho_names = [rho_names[i] for i in selected_ind] 332 | 333 | #sort by most positive to most negative 334 | sort_ind = np.argsort(-np.array(rho_values)) 335 | rho_values = [rho_values[j] for j in sort_ind] 336 | rho_names = [rho_names[j] for j in sort_ind] 337 | rho_values = np.array(rho_values) 338 | 339 | rho_values_string = [str(int(i)) + " points" for i in rho_values] 340 | n_variable_rows = len(rho_values) 341 | total_string = "ADD POINTS FROM ROWS %d to %d" % (1, n_variable_rows) 342 | 343 | max_name_col_length = max(len(predict_string), len(total_string), max([len(s) for s in rho_names])) + 2 344 | max_value_col_length = max(7, max([len(s) for s in rho_values_string]) + len("points")) + 2 345 | 346 | 347 | m = PrettyTable() 348 | m.field_names = ["Variable", "Points", "Tally"] 349 | 350 | m.add_row([predict_string, "", ""]) 351 | m.add_row(['=' * max_name_col_length, "=" * max_value_col_length, "========="]) 352 | 353 | for v in range(0, n_variable_rows): 354 | m.add_row([rho_names[v], rho_values_string[v], "+ ....."]) 355 | 356 | m.add_row(['=' * max_name_col_length, "=" * max_value_col_length, "========="]) 357 | m.add_row([total_string, "SCORE", "= ....."]) 358 | m.header = False 359 | m.align["Variable"] = "l" 360 | m.align["Points"] = "r" 361 | m.align["Tally"] = "r" 362 | return(m) 363 | 364 | def get_rho_summary(rho, slim_info, X, Y): 365 | 366 | #build a pretty table model 367 | printed_model = print_slim_model(rho, X_names = slim_info['X_names'], Y_name = slim_info['Y_name'], show_omitted_variables = False) 368 | 369 | #transform Y 370 | y = np.array(Y.flatten(), dtype = np.float) 371 | pos_ind = y == 1 372 | neg_ind = ~pos_ind 373 | N = len(Y) 374 | N_pos = np.sum(pos_ind) 375 | N_neg = N - N_pos 376 | 377 | #get predictions 378 | yhat = X.dot(rho) > 0 379 | yhat = np.array(yhat, dtype = np.float) 380 | yhat[yhat == 0] = -1 381 | 382 | true_positives = np.sum(yhat[pos_ind] == 1) 383 | false_positives = np.sum(yhat[neg_ind] == 1) 384 | true_negatives= np.sum(yhat[neg_ind] == -1) 385 | false_negatives = np.sum(yhat[pos_ind] == -1) 386 | 387 | rho_summary = { 388 | 'rho': rho, 389 | 'pretty_model': printed_model, 390 | 'string_model': printed_model.get_string(), 391 | 'true_positives': true_positives, 392 | 'true_negatives': true_negatives, 393 | 'false_positives': false_positives, 394 | 'false_negatives': false_negatives, 395 | 'mistakes': np.sum(y != yhat), 396 | 'error_rate': (false_positives + false_negatives) / N, 397 | 'true_positive_rate': true_positives / N_pos, 398 | 'false_positive_rate': false_positives / N_neg, 399 | 'L0_norm': np.sum(rho[slim_info['L0_reg_ind']]), 400 | } 401 | 402 | return(rho_summary) 403 | 404 | def get_slim_summary(slim_IP, slim_info, X, Y): 405 | 406 | #TODO: pull add rho_summary for each solution in solution pool 407 | 408 | #MIP Related Items 409 | slim_summary = { 410 | # 411 | # IP related information 412 | # 413 | 'solution_status_code': slim_IP.solution.get_status(), 414 | 'solution_status': slim_IP.solution.get_status_string(slim_IP.solution.get_status()), 415 | 'objective_value': slim_IP.solution.get_objective_value(), 416 | 'optimality_gap': slim_IP.solution.MIP.get_best_objective(), 417 | 'objval_lowerbound': slim_IP.solution.MIP.get_mip_relative_gap(), 418 | 'simplex_iterations': slim_IP.solution.progress.get_num_iterations(), 419 | 'nodes_processed': slim_IP.solution.progress.get_num_nodes_processed(), 420 | 'nodes_remaining': slim_IP.solution.progress.get_num_nodes_remaining(), 421 | # 422 | # Solution based information (default values) 423 | # 424 | 'rho': np.nan, 425 | 'pretty_model': np.nan, 426 | 'string_model': np.nan, 427 | 'true_positives': np.nan, 428 | 'true_negatives': np.nan, 429 | 'false_positives': np.nan, 430 | 'false_negatives': np.nan, 431 | 'mistakes': np.nan, 432 | 'error_rate': np.nan, 433 | 'true_positive_rate': np.nan, 434 | 'false_positive_rate': np.nan, 435 | 'L0_norm': np.nan, 436 | } 437 | 438 | #Update with Solution-Based Stats 439 | try: 440 | rho = np.array(slim_IP.solution.get_values(slim_info['rho_idx'])) 441 | slim_summary.update(get_rho_summary(rho, slim_info, X, Y)) 442 | except CplexError as e: 443 | print_log(e) 444 | 445 | return(slim_summary) -------------------------------------------------------------------------------- /slim_python/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustunb/slim-python/204c7db64cad0b139e748b299fea672bca9bc81e/slim_python/tests/__init__.py --------------------------------------------------------------------------------