{"id":34086153,"url":"https://github.com/tsitsimis/disjunctive-normal-networks","last_synced_at":"2026-04-10T10:32:22.695Z","repository":{"id":57418499,"uuid":"289691345","full_name":"tsitsimis/disjunctive-normal-networks","owner":"tsitsimis","description":"PyTorch implementation of Disjunctive Normal Networks","archived":false,"fork":false,"pushed_at":"2020-09-18T16:03:44.000Z","size":6189,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-16T16:13:08.841Z","etag":null,"topics":["classification","classification-algorithm","machine-learning","machine-learning-algorithms"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tsitsimis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-23T13:26:54.000Z","updated_at":"2023-05-13T17:48:23.000Z","dependencies_parsed_at":"2022-09-12T12:33:19.520Z","dependency_job_id":null,"html_url":"https://github.com/tsitsimis/disjunctive-normal-networks","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/tsitsimis/disjunctive-normal-networks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsitsimis%2Fdisjunctive-normal-networks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsitsimis%2Fdisjunctive-normal-networks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsitsimis%2Fdisjunctive-normal-networks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsitsimis%2Fdisjunctive-normal-networks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tsitsimis","download_url":"https://codeload.github.com/tsitsimis/disjunctive-normal-networks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsitsimis%2Fdisjunctive-normal-networks/sbom","scorecard":{"id":900845,"data":{"date":"2025-08-11","repo":{"name":"github.com/tsitsimis/disjunctive-normal-networks","commit":"5f4b1c349b0805267bc85df407fe205c50878046"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENCE.txt:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENCE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-6p56-wp2h-9hxr","Warn: Project is vulnerable to: GHSA-fpfv-jqm9-f5jm","Warn: Project is vulnerable to: PYSEC-2024-110 / GHSA-jw8x-6495-233v","Warn: Project is vulnerable to: PYSEC-2020-108 / GHSA-jxfp-4rvq-9h9m","Warn: Project is vulnerable to: GHSA-3749-ghw9-m3mg","Warn: Project is vulnerable to: PYSEC-2022-43015 / GHSA-47fc-vmwq-366v","Warn: Project is vulnerable to: PYSEC-2025-41 / GHSA-53q9-r3pm-6pq6","Warn: Project is vulnerable to: PYSEC-2024-252 / GHSA-5pcm-hx3q-hm94","Warn: Project is vulnerable to: GHSA-887c-mr87-cxwp","Warn: Project is vulnerable to: PYSEC-2024-251 / GHSA-pg7h-5qx3-wjr3","Warn: Project is vulnerable to: PYSEC-2024-250","Warn: Project is vulnerable to: PYSEC-2024-259"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T15:30:48.305Z","repository_id":57418499,"created_at":"2025-08-24T15:30:48.306Z","updated_at":"2025-08-24T15:30:48.306Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31638452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classification","classification-algorithm","machine-learning","machine-learning-algorithms"],"created_at":"2025-12-14T13:23:42.974Z","updated_at":"2026-04-10T10:32:22.681Z","avatar_url":"https://github.com/tsitsimis.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![PyPI version shields.io](https://img.shields.io/pypi/v/disjunctive-nn.svg)](https://pypi.python.org/pypi/disjunctive-nn)\n[![PyPI license](https://img.shields.io/pypi/l/disjunctive-nn.svg)](https://pypi.python.org/pypi/disjunctive-nn/)\n[![PyPI license](https://travis-ci.com/tsitsimis/disjunctive-normal-networks.svg?branch=master)](https://travis-ci.com/tsitsimis/disjunctive-normal-networks.svg?branch=master)\n\n\n# Disjunctive Normal Networks\n![](./assets/polytopes-partition.png)\n\nA Disjunctive Normal Network (DNN) is a special type of Neural Network used for binary classification. It uses intersected convex polytopes (hyperdimensional polygons) to cover the feature space of positive samples. This allows DNNs to find rules in the form of constraining inequalities in feature space that resemble the rules present in Decision Trees (DTs).\n\n In 2D it can be seen as multiple convex polygons spread on the plane enclosing all positive samples while leaving negative samples outside. \n\nBased on paper:\n\u003e Mehdi Sajjadi, Mojtaba Seyedhosseini, Tolga Tasdizen (2014). Disjunctive Normal Networks. CoRR, abs/1412.8534.\n [\\[pdf\\]](https://arxiv.org/pdf/1412.8534.pdf)\n\n\n## How to use disjunctive-nn\nThe disjuntive-nn package inherits from scikit-learn classes, and thus drops in neatly next to other sklearn transformers with an identical calling API.\n\n```python\nfrom disjunctive_nn import DisjunctiveNormalNetwork\nfrom sklearn.datasets import make_moons\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\n\nX, y = make_moons(n_samples=1000, noise=0.2)\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.33, random_state=42)\n    \ndnn = DisjunctiveNormalNetwork(n_polytopes=2, m=4)\ndnn.fit(X_train, y_train)\n\ny_pred = dnn.predict(X_test)\nprint(accuracy_score(y_test, y_pred))\n```\n\n## Installing\nPyPI install:\n```\npip install disjunctive_nn\n```\n\nAlternatively download the package, install requirements, and manually run the installer:\n```\nwget https://github.com/tsitsimis/disjunctive-normal-networks/archive/master.zip\nunzip master.zip\nrm master.zip\ncd disjunctive-normal-networks-master\n\npip install -r requirements.txt\n\npython setup.py install\n```\n\n## Benefits of Disjunctive Normal Networks\nA Disjunctive Normal Network can be seen as an [Oblique Decision Tree](https://www.researchgate.net/publication/260972972_Oblique_Decision_Tree_Learning_Approaches_-_A_Critical_Review) (ODT) learned with backpropagation by minimizing an error function.\n\nOblique Decision Trees are a generalization of regular Decision Trees with rules that are multivariate resulting in dividing the feature space with boundaries non-parallel to the axes.\n\nThis allows DNNs to be much more interpretable (inequality rules on linear combination of features) than a vanilla Neural Network and to be trained with backpropagation.\n\nOverall the main advantages of a DNN over a DT are:\n- Uses polytopes instead of hyercubes\n- Is trained with backpropagation and can be thus incorporated in any neural network topology as final or intermediate step\n- Is less prone to overfitting (although this is a quick result shown by only some simple experiments)\n\n## Theoretical background\n### Disjunctive Normal Form\nA Decision Tree segments the space in hypercubes by drawing axis-aligned hyperplanes. Each hyperbox encloses the points of one class to form the final decision function of the tree\n\n\u003cimg src=\"./assets/decision-tree-boxes.jpg\" height=200/\u003e\n\nIn the case of binary classification, the interior of the hypercubes enclosing the positive samples can be seen as the subspace where a boolean function becomes True (1) and ouside is False (0).\n\n\u003cimg src=\"./assets/decision-tree.png\" height=200/\u003e\n\nFor the tree of the above picture the associated boolean function (1 for positive class \u003cimg src=\"https://render.githubusercontent.com/render/math?math=c_%2B\"\u003e, 0 for class \u003cimg src=\"https://render.githubusercontent.com/render/math?math=c_-\"\u003e) is\n\n\u003cimg src=\"https://render.githubusercontent.com/render/math?math=Y = ((x_1 \u003c a_1) \\cap (x_2 \u003c a_2)) \\cup ((x_1 \u003c a_1) \\cap (x_2 \u003c a_2)^\\prime \\cap (x_3 \u003c a_4)^\\prime) \\cup ((x_1 \u003c a_1)^\\prime \\cap (x_4 \u003c a_4)^\\prime \\cap (x_5 \u003c a_5))\"\u003e\n\nThis boolean function is written in [Disjunctive Normal Form](https://en.wikipedia.org/wiki/Disjunctive_normal_form) meaning that it is a union of intersections or an \"OR of ANDs\" (in terms of logic gates).\n\nHere is when Disjunctive Normal Networks come into play to represent such boolean functions.\n\n### Half-Spaces and Polytopes\nA polytope is the generalization of a polygon and polyhedron in higher dimensions. It can be seen as the intersection of M half-spaces, where a half-space \u003cimg src=\"https://render.githubusercontent.com/render/math?math=H_i\"\u003e is defined as the sub-space where it holds \u003cimg src=\"https://render.githubusercontent.com/render/math?math=h_i(x) \u003e 0\"\u003e\n\n\u003cimg src=\"./assets/polytope.png\" height=140/\u003e\n\nMany such polytopes can be used as covers and optimized to enclose all positive samples in a binary classification problem:\n\n\u003cimg src=\"./assets/polytopes.png\" height=200/\u003e\n\n### Decision Function\nA half-space can be expressed as a sigmoid function of a linear combination of the feature space\n\u003cimg src=\"https://render.githubusercontent.com/render/math?math=h(x) = \\sigma(w^Tx %2B a)\"\u003e. The intersection of M half-spaces is their product (boolean AND) and forms a polytope \u003cimg src=\"https://render.githubusercontent.com/render/math?math=P_i\"\u003e\n\n\u003cimg src=\"https://render.githubusercontent.com/render/math?math=P_i = \\displaystyle \\product_{j=1}^{M} h_{ij}(x)\"\u003e\n\nFinally, the union of N polytopes forms the decision function \u003cimg src=\"https://render.githubusercontent.com/render/math?math=f(x)\"\u003e. To calculate the union we could just add all the \u003cimg src=\"https://render.githubusercontent.com/render/math?math=P_i(x)\"\u003e together but in overlapping areas the result would be greater than 1. To tackle this, using the [DeMorgan](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) rule \u003cimg src=\"https://render.githubusercontent.com/render/math?math=A \\cup B = (A^\\prime \\cap B^\\prime)^\\prime\"\u003e the sum can be transformed to the product\n\n\u003cimg src=\"https://render.githubusercontent.com/render/math?math=f(x) = 1 - \\displaystyle \\product_{i=1}^{N}(\\product_{j=1}^{M} 1 - h_{ij}(x))\"\u003e\n\nIn the above expression we replace boolean negation of a variable \u003cimg src=\"https://render.githubusercontent.com/render/math?math=A\"\u003e with \u003cimg src=\"https://render.githubusercontent.com/render/math?math=1-A\"\u003e and the boolean AND with a product. \n\nThe function \u003cimg src=\"https://render.githubusercontent.com/render/math?math=f(x)\"\u003e is then optimized with gradient descent.\n\n\n## Examples and benchmarking\nDNNs were tested on 2D synthetic datasets and compared to Decision Trees which is the closest classifier in terms of complexity and shape of decision function. The point of this experiment is to illustrate the nature of decision boundaries of the 2 classifiers. This should be taken with a grain of salt, as the performance does not necessarily carry over to real datasets.\n\nThe accuracy corresponds to the test set after splitting the dataset in train and test set. DNN parameters (N: number of polytopes, M: number of half-spaces per polytope) are set through experimentation.\n\n\u003ctable\u003e\n    \u003cth\u003eDataset\u003c/th\u003e\n    \u003cth\u003eDNN\u003c/th\u003e\n    \u003cth\u003eDT\u003c/th\u003e\n    \u003cth\u003eDNN Parameters\u003c/th\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eMoons\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e0.98\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e0.96\u003c/td\u003e\n        \u003ctd\u003eN=2, M=4\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eCircles\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e0.98\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e0.96\u003c/td\u003e\n        \u003ctd\u003eN=1, M=4\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eSpirals\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e0.99\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e0.96\u003c/td\u003e\n        \u003ctd\u003eN=20, M=10\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\nThe below plots show the 2 models' decision function when trained on the whole dataset. The purpose is to show how well the models memorize (overfit) the training set.\n\n### Moons\n\u003cimg src=\"./assets/moons-experiments.png\" width=\"100%\"/\u003e\n\n### Circles\n\u003cimg src=\"./assets/circles-experiments.png\" width=\"100%\"/\u003e\n\n### Spirals\n\u003cimg src=\"./assets/spirals-experiments.png\" width=\"100%\"/\u003e\n\n\nThe overall observation is that DNNs provide much **smoother decision boundaries** and overfit less on training data.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsitsimis%2Fdisjunctive-normal-networks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftsitsimis%2Fdisjunctive-normal-networks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsitsimis%2Fdisjunctive-normal-networks/lists"}