├── .github └── workflows │ ├── doc-build.yml │ ├── release.yml │ ├── snapshot.yml │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── epl.html ├── pom.xml └── src ├── main └── clojure │ └── clojure │ └── algo │ ├── generic.clj │ └── generic │ ├── arithmetic.clj │ ├── collection.clj │ ├── comparison.clj │ ├── functor.clj │ └── math_functions.clj └── test └── clojure └── clojure └── algo └── generic ├── test_collection.clj ├── test_comparison.clj ├── test_complex.clj └── test_functor.clj /.github/workflows/doc-build.yml: -------------------------------------------------------------------------------- 1 | name: Build API Docs 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | call-doc-build-workflow: 8 | uses: clojure/build.ci/.github/workflows/doc-build.yml@master 9 | with: 10 | project: clojure/algo.generic 11 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release on demand 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | releaseVersion: 7 | description: "Version to release" 8 | required: true 9 | snapshotVersion: 10 | description: "Snapshot version after release" 11 | required: true 12 | 13 | jobs: 14 | call-release: 15 | uses: clojure/build.ci/.github/workflows/release.yml@master 16 | with: 17 | releaseVersion: ${{ github.event.inputs.releaseVersion }} 18 | snapshotVersion: ${{ github.event.inputs.snapshotVersion }} 19 | secrets: inherit -------------------------------------------------------------------------------- /.github/workflows/snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Snapshot on demand 2 | 3 | on: [workflow_dispatch] 4 | 5 | jobs: 6 | call-snapshot: 7 | uses: clojure/build.ci/.github/workflows/snapshot.yml@master 8 | secrets: inherit 9 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | call-test: 7 | uses: clojure/build.ci/.github/workflows/test.yml@master 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This is a [Clojure contrib] project. 2 | 3 | Under the Clojure contrib [guidelines], this project cannot accept 4 | pull requests. All patches must be submitted via [JIRA]. 5 | 6 | See [Contributing] on the Clojure website for 7 | more information on how to contribute. 8 | 9 | [Clojure contrib]: https://clojure.org/community/contrib_libs 10 | [Contributing]: https://clojure.org/community/contributing 11 | [JIRA]: http://dev.clojure.org/jira/browse/ALGOG 12 | [guidelines]: https://clojure.org/community/contrib_howto 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' 19 | from a Contributor if it was added to the Program by such Contributor 20 | itself or anyone acting on such Contributor's behalf. Contributions do not 21 | include additions to the Program which: (i) are separate modules of 22 | software distributed in conjunction with the Program under their own 23 | license agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this 32 | Agreement. 33 | 34 | "Recipient" means anyone who receives the Program under this Agreement, 35 | including all Contributors. 36 | 37 | 2. GRANT OF RIGHTS 38 | a) Subject to the terms of this Agreement, each Contributor hereby grants 39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 40 | reproduce, prepare derivative works of, publicly display, publicly 41 | perform, distribute and sublicense the Contribution of such Contributor, 42 | if any, and such derivative works, in source code and object code form. 43 | b) Subject to the terms of this Agreement, each Contributor hereby grants 44 | Recipient a non-exclusive, worldwide, royalty-free patent license under 45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 46 | transfer the Contribution of such Contributor, if any, in source code and 47 | object code form. This patent license shall apply to the combination of 48 | the Contribution and the Program if, at the time the Contribution is 49 | added by the Contributor, such addition of the Contribution causes such 50 | combination to be covered by the Licensed Patents. The patent license 51 | shall not apply to any other combinations which include the Contribution. 52 | No hardware per se is licensed hereunder. 53 | c) Recipient understands that although each Contributor grants the licenses 54 | to its Contributions set forth herein, no assurances are provided by any 55 | Contributor that the Program does not infringe the patent or other 56 | intellectual property rights of any other entity. Each Contributor 57 | disclaims any liability to Recipient for claims brought by any other 58 | entity based on infringement of intellectual property rights or 59 | otherwise. As a condition to exercising the rights and licenses granted 60 | hereunder, each Recipient hereby assumes sole responsibility to secure 61 | any other intellectual property rights needed, if any. For example, if a 62 | third party patent license is required to allow Recipient to distribute 63 | the Program, it is Recipient's responsibility to acquire that license 64 | before distributing the Program. 65 | d) Each Contributor represents that to its knowledge it has sufficient 66 | copyright rights in its Contribution, if any, to grant the copyright 67 | license set forth in this Agreement. 68 | 69 | 3. REQUIREMENTS 70 | 71 | A Contributor may choose to distribute the Program in object code form under 72 | its own license agreement, provided that: 73 | 74 | a) it complies with the terms and conditions of this Agreement; and 75 | b) its license agreement: 76 | i) effectively disclaims on behalf of all Contributors all warranties 77 | and conditions, express and implied, including warranties or 78 | conditions of title and non-infringement, and implied warranties or 79 | conditions of merchantability and fitness for a particular purpose; 80 | ii) effectively excludes on behalf of all Contributors all liability for 81 | damages, including direct, indirect, special, incidental and 82 | consequential damages, such as lost profits; 83 | iii) states that any provisions which differ from this Agreement are 84 | offered by that Contributor alone and not by any other party; and 85 | iv) states that source code for the Program is available from such 86 | Contributor, and informs licensees how to obtain it in a reasonable 87 | manner on or through a medium customarily used for software exchange. 88 | 89 | When the Program is made available in source code form: 90 | 91 | a) it must be made available under this Agreement; and 92 | b) a copy of this Agreement must be included with each copy of the Program. 93 | Contributors may not remove or alter any copyright notices contained 94 | within the Program. 95 | 96 | Each Contributor must identify itself as the originator of its Contribution, 97 | if 98 | any, in a manner that reasonably allows subsequent Recipients to identify the 99 | originator of the Contribution. 100 | 101 | 4. COMMERCIAL DISTRIBUTION 102 | 103 | Commercial distributors of software may accept certain responsibilities with 104 | respect to end users, business partners and the like. While this license is 105 | intended to facilitate the commercial use of the Program, the Contributor who 106 | includes the Program in a commercial product offering should do so in a manner 107 | which does not create potential liability for other Contributors. Therefore, 108 | if a Contributor includes the Program in a commercial product offering, such 109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 110 | every other Contributor ("Indemnified Contributor") against any losses, 111 | damages and costs (collectively "Losses") arising from claims, lawsuits and 112 | other legal actions brought by a third party against the Indemnified 113 | Contributor to the extent caused by the acts or omissions of such Commercial 114 | Contributor in connection with its distribution of the Program in a commercial 115 | product offering. The obligations in this section do not apply to any claims 116 | or Losses relating to any actual or alleged intellectual property 117 | infringement. In order to qualify, an Indemnified Contributor must: 118 | a) promptly notify the Commercial Contributor in writing of such claim, and 119 | b) allow the Commercial Contributor to control, and cooperate with the 120 | Commercial Contributor in, the defense and any related settlement 121 | negotiations. The Indemnified Contributor may participate in any such claim at 122 | its own expense. 123 | 124 | For example, a Contributor might include the Program in a commercial product 125 | offering, Product X. That Contributor is then a Commercial Contributor. If 126 | that Commercial Contributor then makes performance claims, or offers 127 | warranties related to Product X, those performance claims and warranties are 128 | such Commercial Contributor's responsibility alone. Under this section, the 129 | Commercial Contributor would have to defend claims against the other 130 | Contributors related to those performance claims and warranties, and if a 131 | court requires any other Contributor to pay any damages as a result, the 132 | Commercial Contributor must pay those damages. 133 | 134 | 5. NO WARRANTY 135 | 136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 140 | Recipient is solely responsible for determining the appropriateness of using 141 | and distributing the Program and assumes all risks associated with its 142 | exercise of rights under this Agreement , including but not limited to the 143 | risks and costs of program errors, compliance with applicable laws, damage to 144 | or loss of data, programs or equipment, and unavailability or interruption of 145 | operations. 146 | 147 | 6. DISCLAIMER OF LIABILITY 148 | 149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 156 | OF SUCH DAMAGES. 157 | 158 | 7. GENERAL 159 | 160 | If any provision of this Agreement is invalid or unenforceable under 161 | applicable law, it shall not affect the validity or enforceability of the 162 | remainder of the terms of this Agreement, and without further action by the 163 | parties hereto, such provision shall be reformed to the minimum extent 164 | necessary to make such provision valid and enforceable. 165 | 166 | If Recipient institutes patent litigation against any entity (including a 167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 168 | (excluding combinations of the Program with other software or hardware) 169 | infringes such Recipient's patent(s), then such Recipient's rights granted 170 | under Section 2(b) shall terminate as of the date such litigation is filed. 171 | 172 | All Recipient's rights under this Agreement shall terminate if it fails to 173 | comply with any of the material terms or conditions of this Agreement and does 174 | not cure such failure in a reasonable period of time after becoming aware of 175 | such noncompliance. If all Recipient's rights under this Agreement terminate, 176 | Recipient agrees to cease use and distribution of the Program as soon as 177 | reasonably practicable. However, Recipient's obligations under this Agreement 178 | and any licenses granted by Recipient relating to the Program shall continue 179 | and survive. 180 | 181 | Everyone is permitted to copy and distribute copies of this Agreement, but in 182 | order to avoid inconsistency the Agreement is copyrighted and may only be 183 | modified in the following manner. The Agreement Steward reserves the right to 184 | publish new versions (including revisions) of this Agreement from time to 185 | time. No one other than the Agreement Steward has the right to modify this 186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 187 | Eclipse Foundation may assign the responsibility to serve as the Agreement 188 | Steward to a suitable separate entity. Each new version of the Agreement will 189 | be given a distinguishing version number. The Program (including 190 | Contributions) may always be distributed subject to the version of the 191 | Agreement under which it was received. In addition, after a new version of the 192 | Agreement is published, Contributor may elect to distribute the Program 193 | (including its Contributions) under the new version. Except as expressly 194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 195 | licenses to the intellectual property of any Contributor under this Agreement, 196 | whether expressly, by implication, estoppel or otherwise. All rights in the 197 | Program not expressly granted under this Agreement are reserved. 198 | 199 | This Agreement is governed by the laws of the State of New York and the 200 | intellectual property laws of the United States of America. No party to this 201 | Agreement will bring a legal action under this Agreement more than one year 202 | after the cause of action arose. Each party waives its rights to a jury trial in 203 | any resulting litigation. 204 | 205 | 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # algo.generic 2 | 3 | Generic versions of commonly used functions, implemented as multimethods 4 | that can be implemented for any data type. 5 | 6 | ## Usage 7 | 8 | Each submodule of clojure.algo.generic defines a set of related 9 | multimethods that have the same names as their type-specific 10 | counterparts in clojure.core. Implementations for standard Clojure 11 | data types are provided and behave identically to the clojure.core 12 | versions. 13 | 14 | ### Arities 15 | 16 | Arithmetic and comparison functions are defined for the same arities 17 | that the corresponding clojure.core functions support. Arities higher 18 | than 2 are reduced to unary and binary calls. To provide a multimethod 19 | implementation for binary calls with a given pair of types, use 20 | `[type1 type2]` as the dispatch value. For a unary call, the dispatch 21 | value is `type` as usual. Note that `[type1 type2]` is different from 22 | `[type2 type1]` (in most cases you will want to provide both) and that 23 | `[type type]` (binary operation with both arguments of the same type) 24 | is different from `type` (unary operation). 25 | 26 | ### Root type 27 | 28 | This section applies only to binary operations dispatching on type 29 | pairs, and only for types that are *not* Java classes. Types 30 | created by `deftype` and `defrecord` are Java classes, meaning that 31 | most Clojure programmers can go on with the next section. 32 | 33 | One difficulty with binary operations is that there is no predefined 34 | way to provide a default implementation. For single dispatch there is 35 | `:default`, but there is nothing equivalent to `[:default :default]`. 36 | The algo.generic library therefore defines a *root type*, accessible 37 | as `clojure.algo.generic/root-type`, which is used in the default 38 | implementations of binary operations. To integrate your own type into 39 | this system, you must add the clause `(derive my-type 40 | clojure.algo.generic/root-type)` after your type definition. This is 41 | not required for Java classes because `java.lang.Object` is 42 | already derived from `root-type`. 43 | 44 | ### Submodules 45 | 46 | * **algo.generic.arithmetic** provides generic `+` `-` `*` `/` for all 47 | the arities that the corresponding clojure.core functions support. 48 | The minimal implementations required for full arithmetic on a given 49 | type is binary `+` and `*` and unary `-` and `/`. You may wish to 50 | provide explicit implementations for binary `-` and `/` for 51 | efficiency, otherwise the default implementations are `(- a b) => (+ a (- b))` 52 | and `(/ a b) => (* a (/ b))`. 53 | 54 | * **algo.generic.collection** provides generic versions of `assoc`, 55 | `dissoc`, `get`, `conj`, `empty`, `into`, and `seq`. `into` has a 56 | default implementation in terms of `conj` and `seq`, but you may 57 | wish to provide a more efficient one for your types. 58 | 59 | * **algo.generic.comparison** provides the comparison and test 60 | functions `=`, `not=`, `<`, `>`, `<=`, `>=`, `zero?`, `pos?`, 61 | `neg?`, `min`, and ` max`. `not=`, `min`, and `max` cannot be 62 | redefined, they are standard functions that are implemented in 63 | terms of the generic functions of the module. A minimal 64 | implementation of the binary comparison functions consists of 65 | `=` and `>`. Default implementations for `<`, `<=`, and `>=` 66 | call `>`, but more efficient implementations can be provided. 67 | 68 | * **algo.generic.functor** provides a generic mapping operation 69 | called `fmap`. 70 | 71 | * **algo.generic.math-functions** provides generic versions of the 72 | common math functions from `java.lang.Math`, plus `sgn`, `sqr`, and 73 | `conjugate`. 74 | 75 | 76 | ## Releases and dependency information 77 | 78 | Latest stable release: 0.1.3 79 | 80 | * [All released versions](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22algo.generic%22) 81 | 82 | * [Development Snapshot Versions](https://oss.sonatype.org/index.html#nexus-search;gav~org.clojure~algo.generic~~~) 83 | 84 | [CLI/`deps.edn`](https://clojure.org/reference/deps_and_cli) dependency information: 85 | ```clojure 86 | org.clojure/algo.generic {:mvn/version "0.1.3"} 87 | ``` 88 | 89 | [Leiningen](https://github.com/technomancy/leiningen/) dependency information: 90 | 91 | [org.clojure/algo.generic "0.1.3"] 92 | 93 | [Maven](https://maven.apache.org/) dependency information: 94 | 95 | 96 | org.clojure 97 | algo.generic 98 | 0.1.3 99 | 100 | 101 | ## License 102 | 103 | Copyright (c) Rich Hickey and contributors. All rights reserved. 104 | 105 | The use and distribution terms for this software are covered by the 106 | Eclipse Public License 1.0 (https://opensource.org/license/epl-1-0/) 107 | which can be found in the file epl.html at the root of this distribution. 108 | By using this software in any fashion, you are agreeing to be bound by 109 | the terms of this license. 110 | You must not remove this notice, or any other, from this software. 111 | 112 | 113 | -------------------------------------------------------------------------------- /epl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eclipse Public License - Version 1.0 8 | 25 | 26 | 27 | 28 | 29 | 30 |

Eclipse Public License - v 1.0

31 | 32 |

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR 34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS 35 | AGREEMENT.

36 | 37 |

1. DEFINITIONS

38 | 39 |

"Contribution" means:

40 | 41 |

a) in the case of the initial Contributor, the initial 42 | code and documentation distributed under this Agreement, and

43 |

b) in the case of each subsequent Contributor:

44 |

i) changes to the Program, and

45 |

ii) additions to the Program;

46 |

where such changes and/or additions to the Program 47 | originate from and are distributed by that particular Contributor. A 48 | Contribution 'originates' from a Contributor if it was added to the 49 | Program by such Contributor itself or anyone acting on such 50 | Contributor's behalf. Contributions do not include additions to the 51 | Program which: (i) are separate modules of software distributed in 52 | conjunction with the Program under their own license agreement, and (ii) 53 | are not derivative works of the Program.

54 | 55 |

"Contributor" means any person or entity that distributes 56 | the Program.

57 | 58 |

"Licensed Patents" mean patent claims licensable by a 59 | Contributor which are necessarily infringed by the use or sale of its 60 | Contribution alone or when combined with the Program.

61 | 62 |

"Program" means the Contributions distributed in accordance 63 | with this Agreement.

64 | 65 |

"Recipient" means anyone who receives the Program under 66 | this Agreement, including all Contributors.

67 | 68 |

2. GRANT OF RIGHTS

69 | 70 |

a) Subject to the terms of this Agreement, each 71 | Contributor hereby grants Recipient a non-exclusive, worldwide, 72 | royalty-free copyright license to reproduce, prepare derivative works 73 | of, publicly display, publicly perform, distribute and sublicense the 74 | Contribution of such Contributor, if any, and such derivative works, in 75 | source code and object code form.

76 | 77 |

b) Subject to the terms of this Agreement, each 78 | Contributor hereby grants Recipient a non-exclusive, worldwide, 79 | royalty-free patent license under Licensed Patents to make, use, sell, 80 | offer to sell, import and otherwise transfer the Contribution of such 81 | Contributor, if any, in source code and object code form. This patent 82 | license shall apply to the combination of the Contribution and the 83 | Program if, at the time the Contribution is added by the Contributor, 84 | such addition of the Contribution causes such combination to be covered 85 | by the Licensed Patents. The patent license shall not apply to any other 86 | combinations which include the Contribution. No hardware per se is 87 | licensed hereunder.

88 | 89 |

c) Recipient understands that although each Contributor 90 | grants the licenses to its Contributions set forth herein, no assurances 91 | are provided by any Contributor that the Program does not infringe the 92 | patent or other intellectual property rights of any other entity. Each 93 | Contributor disclaims any liability to Recipient for claims brought by 94 | any other entity based on infringement of intellectual property rights 95 | or otherwise. As a condition to exercising the rights and licenses 96 | granted hereunder, each Recipient hereby assumes sole responsibility to 97 | secure any other intellectual property rights needed, if any. For 98 | example, if a third party patent license is required to allow Recipient 99 | to distribute the Program, it is Recipient's responsibility to acquire 100 | that license before distributing the Program.

101 | 102 |

d) Each Contributor represents that to its knowledge it 103 | has sufficient copyright rights in its Contribution, if any, to grant 104 | the copyright license set forth in this Agreement.

105 | 106 |

3. REQUIREMENTS

107 | 108 |

A Contributor may choose to distribute the Program in object code 109 | form under its own license agreement, provided that:

110 | 111 |

a) it complies with the terms and conditions of this 112 | Agreement; and

113 | 114 |

b) its license agreement:

115 | 116 |

i) effectively disclaims on behalf of all Contributors 117 | all warranties and conditions, express and implied, including warranties 118 | or conditions of title and non-infringement, and implied warranties or 119 | conditions of merchantability and fitness for a particular purpose;

120 | 121 |

ii) effectively excludes on behalf of all Contributors 122 | all liability for damages, including direct, indirect, special, 123 | incidental and consequential damages, such as lost profits;

124 | 125 |

iii) states that any provisions which differ from this 126 | Agreement are offered by that Contributor alone and not by any other 127 | party; and

128 | 129 |

iv) states that source code for the Program is available 130 | from such Contributor, and informs licensees how to obtain it in a 131 | reasonable manner on or through a medium customarily used for software 132 | exchange.

133 | 134 |

When the Program is made available in source code form:

135 | 136 |

a) it must be made available under this Agreement; and

137 | 138 |

b) a copy of this Agreement must be included with each 139 | copy of the Program.

140 | 141 |

Contributors may not remove or alter any copyright notices contained 142 | within the Program.

143 | 144 |

Each Contributor must identify itself as the originator of its 145 | Contribution, if any, in a manner that reasonably allows subsequent 146 | Recipients to identify the originator of the Contribution.

147 | 148 |

4. COMMERCIAL DISTRIBUTION

149 | 150 |

Commercial distributors of software may accept certain 151 | responsibilities with respect to end users, business partners and the 152 | like. While this license is intended to facilitate the commercial use of 153 | the Program, the Contributor who includes the Program in a commercial 154 | product offering should do so in a manner which does not create 155 | potential liability for other Contributors. Therefore, if a Contributor 156 | includes the Program in a commercial product offering, such Contributor 157 | ("Commercial Contributor") hereby agrees to defend and 158 | indemnify every other Contributor ("Indemnified Contributor") 159 | against any losses, damages and costs (collectively "Losses") 160 | arising from claims, lawsuits and other legal actions brought by a third 161 | party against the Indemnified Contributor to the extent caused by the 162 | acts or omissions of such Commercial Contributor in connection with its 163 | distribution of the Program in a commercial product offering. The 164 | obligations in this section do not apply to any claims or Losses 165 | relating to any actual or alleged intellectual property infringement. In 166 | order to qualify, an Indemnified Contributor must: a) promptly notify 167 | the Commercial Contributor in writing of such claim, and b) allow the 168 | Commercial Contributor to control, and cooperate with the Commercial 169 | Contributor in, the defense and any related settlement negotiations. The 170 | Indemnified Contributor may participate in any such claim at its own 171 | expense.

172 | 173 |

For example, a Contributor might include the Program in a commercial 174 | product offering, Product X. That Contributor is then a Commercial 175 | Contributor. If that Commercial Contributor then makes performance 176 | claims, or offers warranties related to Product X, those performance 177 | claims and warranties are such Commercial Contributor's responsibility 178 | alone. Under this section, the Commercial Contributor would have to 179 | defend claims against the other Contributors related to those 180 | performance claims and warranties, and if a court requires any other 181 | Contributor to pay any damages as a result, the Commercial Contributor 182 | must pay those damages.

183 | 184 |

5. NO WARRANTY

185 | 186 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY 190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely 191 | responsible for determining the appropriateness of using and 192 | distributing the Program and assumes all risks associated with its 193 | exercise of rights under this Agreement , including but not limited to 194 | the risks and costs of program errors, compliance with applicable laws, 195 | damage to or loss of data, programs or equipment, and unavailability or 196 | interruption of operations.

197 | 198 |

6. DISCLAIMER OF LIABILITY

199 | 200 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT 201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, 202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING 203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF 204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR 206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

208 | 209 |

7. GENERAL

210 | 211 |

If any provision of this Agreement is invalid or unenforceable under 212 | applicable law, it shall not affect the validity or enforceability of 213 | the remainder of the terms of this Agreement, and without further action 214 | by the parties hereto, such provision shall be reformed to the minimum 215 | extent necessary to make such provision valid and enforceable.

216 | 217 |

If Recipient institutes patent litigation against any entity 218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 219 | Program itself (excluding combinations of the Program with other 220 | software or hardware) infringes such Recipient's patent(s), then such 221 | Recipient's rights granted under Section 2(b) shall terminate as of the 222 | date such litigation is filed.

223 | 224 |

All Recipient's rights under this Agreement shall terminate if it 225 | fails to comply with any of the material terms or conditions of this 226 | Agreement and does not cure such failure in a reasonable period of time 227 | after becoming aware of such noncompliance. If all Recipient's rights 228 | under this Agreement terminate, Recipient agrees to cease use and 229 | distribution of the Program as soon as reasonably practicable. However, 230 | Recipient's obligations under this Agreement and any licenses granted by 231 | Recipient relating to the Program shall continue and survive.

232 | 233 |

Everyone is permitted to copy and distribute copies of this 234 | Agreement, but in order to avoid inconsistency the Agreement is 235 | copyrighted and may only be modified in the following manner. The 236 | Agreement Steward reserves the right to publish new versions (including 237 | revisions) of this Agreement from time to time. No one other than the 238 | Agreement Steward has the right to modify this Agreement. The Eclipse 239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may 240 | assign the responsibility to serve as the Agreement Steward to a 241 | suitable separate entity. Each new version of the Agreement will be 242 | given a distinguishing version number. The Program (including 243 | Contributions) may always be distributed subject to the version of the 244 | Agreement under which it was received. In addition, after a new version 245 | of the Agreement is published, Contributor may elect to distribute the 246 | Program (including its Contributions) under the new version. Except as 247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no 248 | rights or licenses to the intellectual property of any Contributor under 249 | this Agreement, whether expressly, by implication, estoppel or 250 | otherwise. All rights in the Program not expressly granted under this 251 | Agreement are reserved.

252 | 253 |

This Agreement is governed by the laws of the State of New York and 254 | the intellectual property laws of the United States of America. No party 255 | to this Agreement will bring a legal action under this Agreement more 256 | than one year after the cause of action arose. Each party waives its 257 | rights to a jury trial in any resulting litigation.

258 | 259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | algo.generic 4 | 1.0.2-SNAPSHOT 5 | algo.generic 6 | 7 | 8 | org.clojure 9 | pom.contrib 10 | 1.3.0 11 | 12 | 13 | 14 | 15 | Konrad Hinsen 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | scm:git:git@github.com:clojure/algo.generic.git 24 | scm:git:git@github.com:clojure/algo.generic.git 25 | git@github.com:clojure/algo.generic.git 26 | HEAD 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic.clj: -------------------------------------------------------------------------------- 1 | ;; Support code for generic interfaces 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | (ns 14 | ^{:author "Konrad Hinsen" 15 | :skip-wiki true 16 | :doc "Generic interfaces 17 | This library provides generic interfaces in the form of 18 | multimethods that can be implemented for any type. 19 | The interfaces partly duplicate existing non-generic 20 | functions in clojure.core (arithmetic, comparison, 21 | collections) and partly provide additional functions that 22 | can be defined for a wide variety of types (functors, math 23 | functions)."} 24 | clojure.algo.generic) 25 | 26 | ; 27 | ; A dispatch function that separates nulary, unary, binary, and 28 | ; higher arity calls and also selects on type for unary and binary 29 | ; calls. 30 | ; 31 | (defn nary-dispatch 32 | ([] ::nulary) 33 | ([x] (type x)) 34 | ([x y] 35 | [(type x) (type y)]) 36 | ([x y & more] ::nary)) 37 | 38 | ; 39 | ; We can't use [::binary :default], so we need to define a root type 40 | ; of the type hierarcy. The derivation for Object covers all classes, 41 | ; but all non-class types will need an explicit derive clause. 42 | ; Since non-class types are rare since Clojure 1.2, this need is 43 | ; not likely to be frequent. 44 | ; 45 | (def root-type ::any) 46 | (derive Object root-type) 47 | 48 | ; 49 | ; Symbols referring to ::nulary and ::n-ary 50 | ; 51 | (def nulary-type ::nulary) 52 | (def nary-type ::nary) 53 | 54 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic/arithmetic.clj: -------------------------------------------------------------------------------- 1 | ;; Generic interfaces for arithmetic operations 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | (ns 14 | ^{:author "Konrad Hinsen" 15 | :doc "Generic arithmetic interface 16 | This library defines generic versions of + - * / as multimethods 17 | that can be defined for any type. The minimal required 18 | implementations for a type are binary + and * plus unary - and /. 19 | Everything else is derived from these automatically. Explicit 20 | binary definitions for - and / can be provided for 21 | efficiency reasons."} 22 | clojure.algo.generic.arithmetic 23 | (:use [clojure.algo.generic 24 | :only (root-type nulary-type nary-type nary-dispatch)]) 25 | (:refer-clojure :exclude [+ - * /])) 26 | 27 | ; 28 | ; Universal zero and one values 29 | ; 30 | (defrecord zero-type []) 31 | (derive zero-type root-type) 32 | (def zero (new zero-type)) 33 | 34 | (defrecord one-type []) 35 | (derive one-type root-type) 36 | (def one (new one-type)) 37 | 38 | ; 39 | ; Addition 40 | ; 41 | ; The minimal implementation is for binary my-type. It is possible 42 | ; in principle to implement [::unary my-type] as well, though this 43 | ; doesn't make any sense. 44 | ; 45 | (defmulti + 46 | "Return the sum of all arguments. The minimal implementation for type 47 | ::my-type is the binary form with dispatch value [::my-type ::my-type]." 48 | {:arglists '([x] [x y] [x y & more])} 49 | nary-dispatch) 50 | 51 | (defmethod + nulary-type 52 | [] 53 | zero) 54 | 55 | (defmethod + root-type 56 | [x] x) 57 | 58 | (defmethod + [root-type zero-type] 59 | [x y] x) 60 | 61 | (defmethod + [zero-type root-type] 62 | [x y] y) 63 | 64 | (defmethod + nary-type 65 | [x y & more] 66 | (if more 67 | (recur (+ x y) (first more) (next more)) 68 | (+ x y))) 69 | 70 | ; 71 | ; Subtraction 72 | ; 73 | ; The minimal implementation is for unary my-type. A default binary 74 | ; implementation is provided as (+ x (- y)), but it is possible to 75 | ; implement unary my-type explicitly for efficiency reasons. 76 | ; 77 | (defmulti - 78 | "Return the difference of the first argument and the sum of all other 79 | arguments. The minimal implementation for type ::my-type is the binary 80 | form with dispatch value [::my-type ::my-type]." 81 | {:arglists '([x] [x y] [x y & more])} 82 | nary-dispatch) 83 | 84 | (defmethod - nulary-type 85 | [] 86 | (throw (java.lang.IllegalArgumentException. 87 | "Wrong number of arguments passed"))) 88 | 89 | (defmethod - [root-type zero-type] 90 | [x y] x) 91 | 92 | (defmethod - [zero-type root-type] 93 | [x y] (- y)) 94 | 95 | (defmethod - [root-type root-type] 96 | [x y] (+ x (- y))) 97 | 98 | (defmethod - nary-type 99 | [x y & more] 100 | (if more 101 | (recur (- x y) (first more) (next more)) 102 | (- x y))) 103 | 104 | ; 105 | ; Multiplication 106 | ; 107 | ; The minimal implementation is for binary [my-type my-type]. It is possible 108 | ; in principle to implement unary my-type as well, though this 109 | ; doesn't make any sense. 110 | ; 111 | (defmulti * 112 | "Return the product of all arguments. The minimal implementation for type 113 | ::my-type is the binary form with dispatch value [::my-type ::my-type]." 114 | {:arglists '([x] [x y] [x y & more])} 115 | nary-dispatch) 116 | 117 | (defmethod * nulary-type 118 | [] 119 | one) 120 | 121 | (defmethod * root-type 122 | [x] x) 123 | 124 | (defmethod * [root-type one-type] 125 | [x y] x) 126 | 127 | (defmethod * [one-type root-type] 128 | [x y] y) 129 | 130 | (defmethod * nary-type 131 | [x y & more] 132 | (if more 133 | (recur (* x y) (first more) (next more)) 134 | (* x y))) 135 | 136 | ; 137 | ; Division 138 | ; 139 | ; The minimal implementation is for unary my-type. A default binary 140 | ; implementation is provided as (* x (/ y)), but it is possible to 141 | ; implement binary [my-type my-type] explicitly for efficiency reasons. 142 | ; 143 | (defmulti / 144 | "Return the quotient of the first argument and the product of all other 145 | arguments. The minimal implementation for type ::my-type is the binary 146 | form with dispatch value [::my-type ::my-type]." 147 | {:arglists '([x] [x y] [x y & more])} 148 | nary-dispatch) 149 | 150 | (defmethod / nulary-type 151 | [] 152 | (throw (java.lang.IllegalArgumentException. 153 | "Wrong number of arguments passed"))) 154 | 155 | (defmethod / [root-type one-type] 156 | [x y] x) 157 | 158 | (defmethod / [one-type root-type] 159 | [x y] (/ y)) 160 | 161 | (defmethod / [root-type root-type] 162 | [x y] (* x (/ y))) 163 | 164 | (defmethod / nary-type 165 | [x y & more] 166 | (if more 167 | (recur (/ x y) (first more) (next more)) 168 | (/ x y))) 169 | 170 | ; 171 | ; Macros to permit access to the / multimethod via namespace qualification 172 | ; 173 | (defmacro defmethod* 174 | "Define a method implementation for the multimethod name in namespace ns. 175 | Required for implementing the division function from another namespace." 176 | [ns name & args] 177 | (let [qsym (symbol (str ns) (str name))] 178 | `(defmethod ~qsym ~@args))) 179 | 180 | (defmacro qsym 181 | "Create the qualified symbol corresponding to sym in namespace ns. 182 | Required to access the division function from another namespace, 183 | e.g. as (qsym clojure.algo.generic.arithmetic /)." 184 | [ns sym] 185 | (symbol (str ns) (str sym))) 186 | 187 | ; 188 | ; Minimal implementations for java.lang.Number 189 | ; 190 | (defmethod + [java.lang.Number java.lang.Number] 191 | [x y] (clojure.core/+ x y)) 192 | 193 | (defmethod - java.lang.Number 194 | [x] (clojure.core/- x)) 195 | 196 | (defmethod * [java.lang.Number java.lang.Number] 197 | [x y] (clojure.core/* x y)) 198 | 199 | (defmethod / java.lang.Number 200 | [x] (clojure.core// x)) 201 | 202 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic/collection.clj: -------------------------------------------------------------------------------- 1 | ;; Generic interfaces for collection-related functions 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | (ns 14 | ^{:author "Konrad Hinsen" 15 | :doc "Generic collection interface 16 | This library defines generic versions of common 17 | collection-related functions as multimethods that can be 18 | defined for any type."} 19 | clojure.algo.generic.collection 20 | (:refer-clojure :exclude [assoc conj dissoc empty get into seq])) 21 | 22 | ; 23 | ; assoc 24 | ; 25 | (defmulti assoc 26 | "Returns a new collection in which the values corresponding to the 27 | given keys are updated by the given values. Each type of collection 28 | can have specific restrictions on the possible keys." 29 | {:arglists '([coll & key-val-pairs])} 30 | (fn [coll & items] (type coll))) 31 | 32 | (defmethod assoc :default 33 | [map & key-val-pairs] 34 | (apply clojure.core/assoc map key-val-pairs)) 35 | 36 | ; 37 | ; conj 38 | ; 39 | (defmulti conj 40 | "Returns a new collection resulting from adding all xs to coll." 41 | {:arglists '([coll & xs])} 42 | (fn [coll & xs] (type coll))) 43 | 44 | (defmethod conj :default 45 | [coll & xs] 46 | (apply clojure.core/conj coll xs)) 47 | 48 | ; 49 | ; dissoc 50 | ; 51 | (defmulti dissoc 52 | "Returns a new collection in which the entries corresponding to the 53 | given keys are removed. Each type of collection can have specific 54 | restrictions on the possible keys." 55 | {:arglists '([coll & keys])} 56 | (fn [coll & keys] (type coll))) 57 | 58 | (defmethod dissoc :default 59 | [map & keys] 60 | (apply clojure.core/dissoc map keys)) 61 | 62 | ; 63 | ; empty 64 | ; 65 | (defmulti empty 66 | "Returns an empty collection of the same kind as the argument" 67 | {:arglists '([coll])} 68 | type) 69 | 70 | (defmethod empty :default 71 | [coll] 72 | (clojure.core/empty coll)) 73 | 74 | ; 75 | ; get 76 | ; 77 | (defmulti get 78 | "Returns the element of coll referred to by key. Each type of collection 79 | can have specific restrictions on the possible keys." 80 | {:arglists '([coll key] [coll key not-found])} 81 | (fn [coll & args] (type coll))) 82 | 83 | (defmethod get :default 84 | ([coll key] 85 | (clojure.core/get coll key)) 86 | ([coll key not-found] 87 | (clojure.core/get coll key not-found))) 88 | 89 | ; 90 | ; into 91 | ; 92 | (defmulti into 93 | "Returns a new coll consisting of to-coll with all of the items of 94 | from-coll conjoined. A default implementation based on reduce, conj, and 95 | seq is provided." 96 | {:arglists '([to from])} 97 | (fn [to from] (type to))) 98 | 99 | (declare seq) 100 | (defmethod into :default 101 | [to from] 102 | (reduce conj to (seq from))) 103 | 104 | ; 105 | ; seq 106 | ; 107 | (defmulti seq 108 | "Returns a seq on the object s." 109 | {:arglists '([s])} 110 | type) 111 | 112 | (defmethod seq :default 113 | [s] 114 | (clojure.core/seq s)) 115 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic/comparison.clj: -------------------------------------------------------------------------------- 1 | ;; Generic interfaces for comparison operations 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | (ns 14 | ^{:author "Konrad Hinsen" 15 | :doc "Generic comparison interface 16 | This library defines generic versions of = not= < > <= >= zero? 17 | as multimethods that can be defined for any type. Of the 18 | greater/less-than relations, types must minimally implement >."} 19 | clojure.algo.generic.comparison 20 | (:refer-clojure :exclude [= not= < > <= >= zero? pos? neg? min max]) 21 | (:use [clojure.algo.generic 22 | :only (root-type nulary-type nary-type nary-dispatch)])) 23 | 24 | ; 25 | ; zero? pos? neg? 26 | ; 27 | (defmulti zero? 28 | "Return true of x is zero." 29 | {:arglists '([x])} 30 | type) 31 | 32 | (defmulti pos? 33 | "Return true of x is positive." 34 | {:arglists '([x])} 35 | type) 36 | 37 | (defmulti neg? 38 | "Return true of x is negative." 39 | {:arglists '([x])} 40 | type) 41 | 42 | ; 43 | ; Equality 44 | ; 45 | (defmulti = 46 | "Return true if all arguments are equal. The minimal implementation for type 47 | ::my-type is the binary form with dispatch value [::my-type ::my-type]." 48 | {:arglists '([x] [x y] [x y & more])} 49 | nary-dispatch) 50 | 51 | (defmethod = root-type 52 | [x] true) 53 | 54 | (defmethod = nary-type 55 | [x y & more] 56 | (if (= x y) 57 | (if (next more) 58 | (recur y (first more) (next more)) 59 | (= y (first more))) 60 | false)) 61 | 62 | (defn not= 63 | "Equivalent to (not (= ...))." 64 | [& args] 65 | (not (apply = args))) 66 | 67 | ; 68 | ; Greater-than 69 | ; 70 | (defmulti > 71 | "Return true if each argument is larger than the following ones. 72 | The minimal implementation for type ::my-type is the binary form 73 | with dispatch value [::my-type ::my-type]." 74 | {:arglists '([x] [x y] [x y & more])} 75 | nary-dispatch) 76 | 77 | (defmethod > root-type 78 | [x] true) 79 | 80 | (defmethod > nary-type 81 | [x y & more] 82 | (if (> x y) 83 | (if (next more) 84 | (recur y (first more) (next more)) 85 | (> y (first more))) 86 | false)) 87 | 88 | ; 89 | ; Less-than defaults to greater-than with arguments inversed 90 | ; 91 | (defmulti < 92 | "Return true if each argument is smaller than the following ones. 93 | The minimal implementation for type ::my-type is the binary form 94 | with dispatch value [::my-type ::my-type]. A default implementation 95 | is provided in terms of >." 96 | {:arglists '([x] [x y] [x y & more])} 97 | nary-dispatch) 98 | 99 | (defmethod < root-type 100 | [x] true) 101 | 102 | (defmethod < [root-type root-type] 103 | [x y] 104 | (> y x)) 105 | 106 | (defmethod < nary-type 107 | [x y & more] 108 | (if (< x y) 109 | (if (next more) 110 | (recur y (first more) (next more)) 111 | (< y (first more))) 112 | false)) 113 | 114 | ; 115 | ; Greater-or-equal defaults to (complement <) 116 | ; 117 | (defmulti >= 118 | "Return true if each argument is larger than or equal to the following 119 | ones. The minimal implementation for type ::my-type is the binary form 120 | with dispatch value [::my-type ::my-type]. A default implementation 121 | is provided in terms of <." 122 | {:arglists '([x] [x y] [x y & more])} 123 | nary-dispatch) 124 | 125 | (defmethod >= root-type 126 | [x] true) 127 | 128 | (defmethod >= [root-type root-type] 129 | [x y] 130 | (not (< x y))) 131 | 132 | (defmethod >= nary-type 133 | [x y & more] 134 | (if (>= x y) 135 | (if (next more) 136 | (recur y (first more) (next more)) 137 | (>= y (first more))) 138 | false)) 139 | 140 | ; 141 | ; Less-than defaults to (complement >) 142 | ; 143 | (defmulti <= 144 | "Return true if each arguments is smaller than or equal to the following 145 | ones. The minimal implementation for type ::my-type is the binary form 146 | with dispatch value [::my-type ::my-type]. A default implementation 147 | is provided in terms of >." 148 | {:arglists '([x] [x y] [x y & more])} 149 | nary-dispatch) 150 | 151 | (defmethod <= root-type 152 | [x] true) 153 | 154 | (defmethod <= [root-type root-type] 155 | [x y] 156 | (not (> x y))) 157 | 158 | (defmethod <= nary-type 159 | [x y & more] 160 | (if (<= x y) 161 | (if (next more) 162 | (recur y (first more) (next more)) 163 | (<= y (first more))) 164 | false)) 165 | 166 | ; 167 | ; Implementations for Clojure's built-in types 168 | ; 169 | (defmethod zero? java.lang.Number 170 | [x] 171 | (clojure.core/zero? x)) 172 | 173 | (defmethod pos? java.lang.Number 174 | [x] 175 | (clojure.core/pos? x)) 176 | 177 | (defmethod neg? java.lang.Number 178 | [x] 179 | (clojure.core/neg? x)) 180 | 181 | (defmethod = [root-type root-type] 182 | [x y] 183 | (clojure.core/= x y)) 184 | 185 | (defmethod > [java.lang.Number java.lang.Number] 186 | [x y] 187 | (clojure.core/> x y)) 188 | 189 | (defmethod < [java.lang.Number java.lang.Number] 190 | [x y] 191 | (clojure.core/< x y)) 192 | 193 | (defmethod >= [java.lang.Number java.lang.Number] 194 | [x y] 195 | (clojure.core/>= x y)) 196 | 197 | (defmethod <= [java.lang.Number java.lang.Number] 198 | [x y] 199 | (clojure.core/<= x y)) 200 | 201 | ; 202 | ; Functions defined in terms of the comparison operators 203 | ; 204 | (defn max 205 | "Returns the greatest of its arguments. Like clojure.core/max except that 206 | is uses generic comparison functions implementable for any data type." 207 | ([x] x) 208 | ([x y] (if (> x y) x y)) 209 | ([x y & more] 210 | (reduce max (max x y) more))) 211 | 212 | (defn min 213 | "Returns the least of its arguments. Like clojure.core/min except that 214 | is uses generic comparison functions implementable for any data type." 215 | ([x] x) 216 | ([x y] (if (< x y) x y)) 217 | ([x y & more] 218 | (reduce min (min x y) more))) 219 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic/functor.clj: -------------------------------------------------------------------------------- 1 | ;; Generic interface for functors 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | (ns 14 | ^{:author "Konrad Hinsen" 15 | :doc "Generic functor interface (fmap)"} 16 | clojure.algo.generic.functor) 17 | 18 | 19 | (defmulti fmap 20 | "Applies function f to each item in the data structure s and returns 21 | a structure of the same kind." 22 | {:arglists '([f s])} 23 | (fn [f s] (type s))) 24 | 25 | (defmethod fmap clojure.lang.IPersistentList 26 | [f v] 27 | (map f v)) 28 | 29 | (defmethod fmap clojure.lang.IPersistentVector 30 | [f v] 31 | (into (empty v) (map f v))) 32 | 33 | (defmethod fmap clojure.lang.IPersistentMap 34 | [f m] 35 | (into (empty m) (for [[k v] m] [k (f v)]))) 36 | 37 | (defmethod fmap clojure.lang.IPersistentSet 38 | [f s] 39 | (into (empty s) (map f s))) 40 | 41 | (defmethod fmap clojure.lang.IFn 42 | [f fn] 43 | (comp f fn)) 44 | 45 | (prefer-method fmap clojure.lang.IPersistentVector clojure.lang.IFn) 46 | (prefer-method fmap clojure.lang.IPersistentMap clojure.lang.IFn) 47 | (prefer-method fmap clojure.lang.IPersistentSet clojure.lang.IFn) 48 | (prefer-method fmap clojure.lang.IPersistentList clojure.lang.ISeq) 49 | 50 | (defmethod fmap clojure.lang.ISeq 51 | [f s] 52 | (map f s)) 53 | 54 | (defmethod fmap java.util.concurrent.Future 55 | [f o] 56 | (future (f @o))) 57 | 58 | (defmethod fmap clojure.lang.Delay 59 | [f d] 60 | (delay (f @d))) 61 | 62 | (defmethod fmap nil 63 | [_ _] 64 | nil) 65 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/algo/generic/math_functions.clj: -------------------------------------------------------------------------------- 1 | ;; Generic interfaces for mathematical functions 2 | 3 | ;; by Konrad Hinsen 4 | 5 | ;; Copyright (c) Konrad Hinsen, 2009-2011. All rights reserved. The use 6 | ;; and distribution terms for this software are covered by the Eclipse 7 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 8 | ;; which can be found in the file epl-v10.html at the root of this 9 | ;; distribution. By using this software in any fashion, you are 10 | ;; agreeing to be bound by the terms of this license. You must not 11 | ;; remove this notice, or any other, from this software. 12 | 13 | ;; Cort Spellman, 2015: 14 | ;; Changes of abs and round to be manually defined for various types instead 15 | ;; of via defmathfn-1. 16 | 17 | (ns 18 | ^{:author "Konrad Hinsen" 19 | :doc "Generic math function interface 20 | This library defines generic versions of common mathematical 21 | functions such as sqrt or sin as multimethods that can be 22 | defined for any type."} 23 | clojure.algo.generic.math-functions 24 | (:refer-clojure :exclude [abs]) 25 | (:require [clojure.algo.generic.arithmetic :as ga] 26 | [clojure.algo.generic.comparison :as gc])) 27 | 28 | ; This used to be in clojure.contrib.def (by Steve Gilardi), 29 | ; which has not been migrated to the new contrib collection. 30 | (defmacro defmacro- 31 | "Same as defmacro but yields a private definition" 32 | [name & decls] 33 | (list* `defmacro (with-meta name (assoc (meta name) :private true)) decls)) 34 | 35 | ; One-argument math functions 36 | (defmacro- defmathfn-1 37 | [name] 38 | (let [java-symbol (symbol "java.lang.Math" (str name))] 39 | `(do 40 | (defmulti ~name 41 | ~(str "Return the " name " of x.") 42 | {:arglists '([~'x])} 43 | type) 44 | (defmethod ~name java.lang.Number 45 | [~'x] 46 | (~java-symbol ~'x))))) 47 | 48 | (defn- two-types [x y] [(type x) (type y)]) 49 | 50 | ; Two-argument math functions 51 | (defmacro- defmathfn-2 52 | [name] 53 | (let [java-symbol (symbol "java.lang.Math" (str name))] 54 | `(do 55 | (defmulti ~name 56 | ~(str "Return the " name " of x and y.") 57 | {:arglists '([~'x ~'y])} 58 | two-types) 59 | (defmethod ~name [java.lang.Number java.lang.Number] 60 | [~'x ~'y] 61 | (~java-symbol ~'x ~'y))))) 62 | 63 | ; List of math functions taken from 64 | ; http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html 65 | (defmathfn-1 acos) 66 | (defmathfn-1 asin) 67 | (defmathfn-1 atan) 68 | (defmathfn-2 atan2) 69 | (defmathfn-1 ceil) 70 | (defmathfn-1 cos) 71 | (defmathfn-1 exp) 72 | (defmathfn-1 floor) 73 | (defmathfn-1 log) 74 | (defmathfn-2 pow) 75 | (defmathfn-1 rint) 76 | (defmathfn-1 sin) 77 | (defmathfn-1 sqrt) 78 | (defmathfn-1 tan) 79 | 80 | ; 81 | ; Absolute value 82 | ; defmathfn-1 only works for types of numbers for which java.Math has an abs 83 | ; method: 84 | ; * java.math.BigInteger and java.math.BigDecimal classes define their own abs 85 | ; methods. 86 | ; * clojure.lang.BigInt may internally be a long or a BigInteger but in either 87 | ; case clojure.lang.BigInt does not have an abs method. 88 | ; * clojure.lang.Ratio does not have an abs method. 89 | ; 90 | (defmulti abs 91 | "Return the absolute value of x. If x is a BigDecimal, abs takes an optional 92 | math-context argument." 93 | {:arglists '([x] [x math-context])} 94 | (fn [x & more] (type x))) 95 | 96 | (defmethod abs :default 97 | [x] 98 | (cond (gc/neg? x) (- x) 99 | :else x)) 100 | 101 | (defmethod abs java.lang.Number 102 | [x] 103 | (java.lang.Math/abs x)) 104 | 105 | (defmethod abs java.math.BigDecimal 106 | ([x] 107 | (.abs x)) 108 | ([x math-context] 109 | (.abs x math-context))) 110 | 111 | (defmethod abs java.math.BigInteger 112 | [x] 113 | (.abs x)) 114 | 115 | (defmethod abs clojure.lang.BigInt 116 | [x] 117 | (if (nil? (.bipart x)) 118 | (clojure.lang.BigInt/fromLong (abs (.lpart x))) 119 | (clojure.lang.BigInt/fromBigInteger (abs (.bipart x))))) 120 | 121 | (defmethod abs clojure.lang.Ratio 122 | [x] 123 | (/ (abs (numerator x)) 124 | (abs (denominator x)))) 125 | 126 | ; 127 | ; Round 128 | ; defmathfn-1 only works for types of numbers for which java.Math has an abs 129 | ; method: 130 | ; * java.math.BigInteger and java.math.BigDecimal classes define their own round 131 | ; methods. 132 | ; * clojure.lang.BigInt may internally be a long or a BigInteger but in either 133 | ; case clojure.lang.BigInt does not have an round method. 134 | ; * clojure.lang.Ratio does not have an round method. 135 | ; 136 | (defmulti round 137 | "Round x. 138 | If x is a BigDecimal, a math-context argument is also required: 139 | (round x math-context) 140 | If x is a Ratio, 141 | (round x) converts x to a double and rounds; 142 | (round x math-context) converts x to a BigDecimal and rounds." 143 | {:arglists '([x] [x math-context])} 144 | (fn [x & more] (type x))) 145 | 146 | (doseq [c [java.lang.Float 147 | java.lang.Double]] 148 | (defmethod round c [x] (java.lang.Math/round x))) 149 | 150 | (doseq [c [java.lang.Byte 151 | java.lang.Short 152 | java.lang.Integer 153 | java.lang.Long 154 | java.math.BigInteger 155 | clojure.lang.BigInt]] 156 | (defmethod round c [x] x)) 157 | 158 | (defmethod round java.math.BigDecimal 159 | [x math-context] 160 | (.round x math-context)) 161 | 162 | (defmethod round clojure.lang.Ratio 163 | ([x] 164 | (round (double x))) 165 | ([x math-context] 166 | (round (bigdec x) math-context))) 167 | 168 | 169 | ; 170 | ; Sign 171 | ; 172 | (defmulti sgn 173 | "Return the sign of x (-1, 0, or 1)." 174 | {:arglists '([x])} 175 | type) 176 | 177 | (defmethod sgn :default 178 | [x] 179 | (cond (gc/zero? x) 0 180 | (gc/> x 0) 1 181 | :else -1)) 182 | 183 | ; 184 | ; Conjugation 185 | ; 186 | (defmulti conjugate 187 | "Return the conjugate of x." 188 | {:arglists '([x])} 189 | type) 190 | 191 | (defmethod conjugate :default 192 | [x] x) 193 | 194 | ; 195 | ; Square 196 | ; 197 | (defmulti sqr 198 | "Return the square of x." 199 | {:arglists '([x])} 200 | type) 201 | 202 | (defmethod sqr :default 203 | [x] 204 | (ga/* x x)) 205 | 206 | ; 207 | ; Approximate equality for use with floating point types 208 | ; 209 | (defn approx= 210 | "Return true if the absolute value of the difference between x and y 211 | is less than eps." 212 | [x y eps] 213 | (gc/< (abs (ga/- x y)) eps)) 214 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/algo/generic/test_collection.clj: -------------------------------------------------------------------------------- 1 | ;; Test routines for clojure.algo.generic.collection 2 | 3 | ;; Copyright (c) Konrad Hinsen, 2011. All rights reserved. The use 4 | ;; and distribution terms for this software are covered by the Eclipse 5 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 6 | ;; which can be found in the file epl-v10.html at the root of this 7 | ;; distribution. By using this software in any fashion, you are 8 | ;; agreeing to be bound by the terms of this license. You must not 9 | ;; remove this notice, or any other, from this software. 10 | 11 | (ns clojure.algo.generic.test-collection 12 | (:use [clojure.test :only (deftest is are run-tests)]) 13 | (:require [clojure.algo.generic.collection :as gc])) 14 | 15 | ; Define a multiset class. The representation is a map from values to counts. 16 | (defrecord multiset [map]) 17 | 18 | (defn mset 19 | [& elements] 20 | (gc/into (new multiset {}) elements)) 21 | 22 | ; Implement the collection multimethods. 23 | (defmethod gc/conj multiset 24 | ([ms x] 25 | (let [msmap (:map ms)] 26 | (new multiset (assoc msmap x (inc (get msmap x 0)))))) 27 | ([ms x & xs] 28 | (reduce gc/conj (gc/conj ms x) xs))) 29 | 30 | (defmethod gc/empty multiset 31 | [ms] 32 | (new multiset {})) 33 | 34 | (defmethod gc/seq multiset 35 | [ms] 36 | (apply concat (map (fn [[x n]] (repeat n x)) (:map ms)))) 37 | 38 | ; Define a sparse vector class. The representation is a map from 39 | ; integer indices to values. 40 | (defrecord sparse-vector [map]) 41 | 42 | (defn s-vector 43 | [& values] 44 | (apply gc/conj (new sparse-vector {}) values)) 45 | 46 | ; Implement the collection multimethods 47 | (defmethod gc/assoc sparse-vector 48 | [sv key value] 49 | (assert (integer? key)) 50 | (assert (not (neg? key))) 51 | (new sparse-vector 52 | (if (nil? value) 53 | (:map sv) 54 | (assoc (:map sv) key value)))) 55 | 56 | (defmethod gc/get sparse-vector 57 | ([sv key] 58 | (gc/get sv key nil)) 59 | ([sv key default] 60 | (get (:map sv) key default))) 61 | 62 | (defmethod gc/conj sparse-vector 63 | [sv & xs] 64 | (loop [svmap (:map sv) 65 | index (inc (apply max (conj (keys svmap) -1))) 66 | xs xs] 67 | (if (empty? xs) 68 | (new sparse-vector svmap) 69 | (recur (if (nil? (first xs)) 70 | svmap 71 | (assoc svmap index (first xs))) 72 | (inc index) (rest xs))))) 73 | 74 | (defmethod gc/empty sparse-vector 75 | [sv] 76 | (new sparse-vector {})) 77 | 78 | (defmethod gc/seq sparse-vector 79 | [sv] 80 | (let [svmap (:map sv) 81 | max-index (apply max (conj (keys svmap) -1))] 82 | (if (neg? max-index) 83 | nil 84 | (for [i (range (inc max-index))] (get svmap i nil))))) 85 | 86 | ; Multiset tests 87 | (deftest multiset-tests 88 | (are [a b] (= a b) 89 | (mset :a :a :b) (mset :a :b :a) 90 | (gc/conj (mset) :a) (mset :a) 91 | (gc/conj (mset) :b :a :b :a) (mset :a :a :b :b) 92 | (gc/empty (mset :a)) (mset) 93 | (gc/seq (mset :a :a :a)) '(:a :a :a))) 94 | 95 | ; Sparse vector tests 96 | (deftest sparse-vector-tests 97 | (are [a b] (= a b) 98 | (gc/empty (s-vector)) (s-vector) 99 | (gc/conj (s-vector 1 2) 3) (s-vector 1 2 3) 100 | (gc/assoc (s-vector 1 2) 2 3) (s-vector 1 2 3) 101 | (gc/assoc (s-vector 1 2) 4 3) (s-vector 1 2 nil nil 3) 102 | (gc/get (s-vector 1 2 3) 1) 2 103 | (gc/seq (gc/assoc (s-vector 1) 3 3)) '(1 nil nil 3))) 104 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/algo/generic/test_comparison.clj: -------------------------------------------------------------------------------- 1 | ;; Test routines for clojure.algo.generic.comparison 2 | 3 | ;; Copyright (c) Konrad Hinsen, 2011. All rights reserved. The use 4 | ;; and distribution terms for this software are covered by the Eclipse 5 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 6 | ;; which can be found in the file epl-v10.html at the root of this 7 | ;; distribution. By using this software in any fashion, you are 8 | ;; agreeing to be bound by the terms of this license. You must not 9 | ;; remove this notice, or any other, from this software. 10 | 11 | (ns clojure.algo.generic.test-comparison 12 | (:use [clojure.test :only (deftest is are run-tests)]) 13 | (:require [clojure.algo.generic.comparison :as gc])) 14 | 15 | ; Define a class that wraps a number. 16 | (defrecord my-number [value]) 17 | (defn n [value] (new my-number value)) 18 | 19 | ; Implement the minimal comparison multimethods. 20 | (defmethod gc/zero? my-number 21 | [x] 22 | (zero? (:value x))) 23 | 24 | (defmethod gc/= [my-number my-number] 25 | [x y] 26 | (= (:value x) (:value y))) 27 | 28 | (defmethod gc/> [my-number my-number] 29 | [x y] 30 | (> (:value x) (:value y))) 31 | 32 | ; Basic tests 33 | (deftest number-comparison 34 | (is (gc/zero? (n 0))) 35 | (is (not (gc/zero? (n 1)))) 36 | (is (gc/= (n 2) (n 2))) 37 | (is (gc/not= (n 2) (n 3))) 38 | (is (gc/> (n 3) (n 2))) 39 | (is (gc/>= (n 3) (n 2))) 40 | (is (gc/< (n 2) (n 3))) 41 | (is (gc/<= (n 2) (n 3))) 42 | (is (gc/>= (n 2) (n 2))) 43 | (is (gc/<= (n 2) (n 2)))) 44 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/algo/generic/test_complex.clj: -------------------------------------------------------------------------------- 1 | ;; Test routines for clojure.algo.generic.arithmetic 2 | ;; and clojure.algo.generic.math_functions. 3 | 4 | ;; Copyright (c) Konrad Hinsen, 2011. All rights reserved. The use 5 | ;; and distribution terms for this software are covered by the Eclipse 6 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 7 | ;; which can be found in the file epl-v10.html at the root of this 8 | ;; distribution. By using this software in any fashion, you are 9 | ;; agreeing to be bound by the terms of this license. You must not 10 | ;; remove this notice, or any other, from this software. 11 | 12 | (ns clojure.algo.generic.test-complex 13 | (:use [clojure.test :only (deftest is are run-tests)] 14 | [clojure.algo.generic :only (root-type)]) 15 | (:require [clojure.algo.generic.arithmetic :as ga] 16 | [clojure.algo.generic.math-functions :as gmf] 17 | [clojure.algo.generic.comparison :as gc])) 18 | 19 | ; Define a basic complex number type 20 | (defrecord complex-number [real imag]) 21 | 22 | (defn complex 23 | [real imag] 24 | (new complex-number real imag)) 25 | 26 | (defn real 27 | [c] 28 | (:real c)) 29 | 30 | (defn imag 31 | [c] 32 | (:imag c)) 33 | 34 | ; Minimal implementation of generic.comparison to facilitate testing 35 | (defmethod gc/zero? complex-number 36 | [x] 37 | (and (zero? (real x)) (zero? (imag x)))) 38 | 39 | (defmethod gc/= [complex-number complex-number] 40 | [x y] 41 | (and (gc/= (real x) (real y)) 42 | (gc/= (imag x) (imag y)))) 43 | 44 | (defmethod gc/= [complex-number root-type] 45 | [x y] 46 | (and (gc/zero? (imag x)) (gc/= (real x) y))) 47 | 48 | (defmethod gc/= [root-type complex-number] 49 | [x y] 50 | (and (gc/zero? (imag y)) (gc/= x (real y)))) 51 | 52 | ; Arithmetic 53 | (defmethod ga/+ [complex-number complex-number] 54 | [x y] 55 | (complex (ga/+ (real x) (real y)) (ga/+ (imag x) (imag y)))) 56 | 57 | (defmethod ga/+ [complex-number root-type] 58 | [x y] 59 | (complex (ga/+ (real x) y) (imag x))) 60 | 61 | (defmethod ga/+ [root-type complex-number] 62 | [x y] 63 | (complex (ga/+ x (real y)) (imag y))) 64 | 65 | (defmethod ga/- complex-number 66 | [x] 67 | (complex (ga/- (real x)) (ga/- (imag x)))) 68 | 69 | (defmethod ga/* [complex-number complex-number] 70 | [x y] 71 | (complex (ga/- (ga/* (real x) (real y)) (ga/* (imag x) (imag y))) 72 | (ga/+ (ga/* (real x) (imag y)) (ga/* (imag x) (real y))))) 73 | 74 | (defmethod ga/* [complex-number root-type] 75 | [x y] 76 | (complex (ga/* (real x) y) (ga/* (imag x) y))) 77 | 78 | (defmethod ga/* [root-type complex-number] 79 | [x y] 80 | (complex (ga/* x (real y)) (ga/* x (imag y)))) 81 | 82 | (ga/defmethod* ga / complex-number 83 | [x] 84 | (let [rx (real x) 85 | ix (imag x) 86 | den ((ga/qsym ga /) (ga/+ (ga/* rx rx) (ga/* ix ix)))] 87 | (complex (ga/* rx den) (ga/- (ga/* ix den))))) 88 | 89 | ; Math functions 90 | (defmethod gmf/conjugate complex-number 91 | [x] 92 | (complex (real x) (ga/- (imag x)))) 93 | 94 | (defmethod gmf/abs complex-number 95 | [x] 96 | (let [r (real x) 97 | i (imag x)] 98 | (gmf/sqrt (ga/+ (ga/* r r) (ga/* i i))))) 99 | 100 | (let [one-half (/ 1 2) 101 | one-eighth (/ 1 8)] 102 | (defmethod gmf/sqrt complex-number 103 | [x] 104 | (let [[r i] (vals x)] 105 | (if (and (gc/zero? r) (gc/zero? i)) 106 | 0 107 | (let [; The basic formula would say 108 | ; abs (gmf/sqrt (ga/+ (ga/* r r) (ga/* i i))) 109 | ; p (gmf/sqrt (ga/* one-half (ga/+ abs r))) 110 | ; but the slightly more complicated one below 111 | ; avoids overflow for large r or i. 112 | ar (gmf/abs r) 113 | ai (gmf/abs i) 114 | r8 (ga/* one-eighth ar) 115 | i8 (ga/* one-eighth ai) 116 | abs (gmf/sqrt (ga/+ (ga/* r8 r8) (ga/* i8 i8))) 117 | p (ga/* 2 (gmf/sqrt (ga/+ abs r8))) 118 | q ((ga/qsym ga /) ai (ga/* 2 p)) 119 | s (gmf/sgn i)] 120 | (if (gc/< r 0) 121 | (complex q (ga/* s p)) 122 | (complex p (ga/* s q)))))))) 123 | 124 | (defmethod gmf/exp complex-number 125 | [x] 126 | (let [r (real x) 127 | i (imag x) 128 | exp-r (gmf/exp r) 129 | cos-i (gmf/cos i) 130 | sin-i (gmf/sin i)] 131 | (complex (ga/* exp-r cos-i) (ga/* exp-r sin-i)))) 132 | 133 | ; Complex number tests 134 | (deftest complex-addition 135 | (is (gc/= (ga/+ (complex 1 2) (complex 1 2)) (complex 2 4))) 136 | (is (gc/= (ga/+ (complex 1 2) (complex -3 -7)) (complex -2 -5))) 137 | (is (gc/= (ga/+ (complex -3 -7) (complex 1 2)) (complex -2 -5))) 138 | (is (gc/= (ga/+ (complex 1 2) 3) (complex 4 2))) 139 | (is (gc/= (ga/+ 3 (complex 1 2)) (complex 4 2))) 140 | (is (gc/= (ga/+ (complex -3 -7) (complex 1 2)) (complex -2 -5))) 141 | (is (gc/= (ga/+ (complex 1 2) (complex -3 -7)) (complex -2 -5))) 142 | (is (gc/= (ga/+ (complex -3 -7) (complex -3 -7)) (complex -6 -14))) 143 | (is (gc/= (ga/+ (complex -3 -7) -1) (complex -4 -7))) 144 | (is (gc/= (ga/+ -1 (complex -3 -7)) (complex -4 -7))) 145 | (is (gc/= (ga/+ 3 (complex 1 2)) (complex 4 2))) 146 | (is (gc/= (ga/+ (complex 1 2) 3) (complex 4 2))) 147 | (is (gc/= (ga/+ -1 (complex -3 -7)) (complex -4 -7))) 148 | (is (gc/= (ga/+ (complex -3 -7) -1) (complex -4 -7)))) 149 | 150 | (deftest complex-subtraction 151 | (is (gc/= (ga/- (complex 1 2) (complex 1 2)) 0)) 152 | (is (gc/= (ga/- (complex 1 2) (complex -3 -7)) (complex 4 9))) 153 | (is (gc/= (ga/- (complex -3 -7) (complex 1 2)) (complex -4 -9))) 154 | (is (gc/= (ga/- (complex 1 2) 3) (complex -2 2))) 155 | (is (gc/= (ga/- 3 (complex 1 2)) (complex 2 -2))) 156 | (is (gc/= (ga/- (complex 1 2) -1) (complex 2 2))) 157 | (is (gc/= (ga/- -1 (complex 1 2)) (complex -2 -2))) 158 | (is (gc/= (ga/- (complex -3 -7) (complex 1 2)) (complex -4 -9))) 159 | (is (gc/= (ga/- (complex 1 2) (complex -3 -7)) (complex 4 9))) 160 | (is (gc/= (ga/- (complex -3 -7) (complex -3 -7)) 0)) 161 | (is (gc/= (ga/- (complex -3 -7) 3) (complex -6 -7))) 162 | (is (gc/= (ga/- 3 (complex -3 -7)) (complex 6 7))) 163 | (is (gc/= (ga/- (complex -3 -7) -1) (complex -2 -7))) 164 | (is (gc/= (ga/- -1 (complex -3 -7)) (complex 2 7))) 165 | (is (gc/= (ga/- 3 (complex 1 2)) (complex 2 -2))) 166 | (is (gc/= (ga/- (complex 1 2) 3) (complex -2 2))) 167 | (is (gc/= (ga/- 3 (complex -3 -7)) (complex 6 7))) 168 | (is (gc/= (ga/- (complex -3 -7) 3) (complex -6 -7))) 169 | (is (gc/= (ga/- -1 (complex 1 2)) (complex -2 -2))) 170 | (is (gc/= (ga/- (complex 1 2) -1) (complex 2 2))) 171 | (is (gc/= (ga/- -1 (complex -3 -7)) (complex 2 7))) 172 | (is (gc/= (ga/- (complex -3 -7) -1) (complex -2 -7)))) 173 | 174 | (deftest complex-multiplication 175 | (is (gc/= (ga/* (complex 1 2) (complex 1 2)) (complex -3 4))) 176 | (is (gc/= (ga/* (complex 1 2) (complex -3 -7)) (complex 11 -13))) 177 | (is (gc/= (ga/* (complex -3 -7) (complex 1 2)) (complex 11 -13))) 178 | (is (gc/= (ga/* (complex 1 2) 3) (complex 3 6))) 179 | (is (gc/= (ga/* 3 (complex 1 2)) (complex 3 6))) 180 | (is (gc/= (ga/* (complex 1 2) -1) (complex -1 -2))) 181 | (is (gc/= (ga/* -1 (complex 1 2)) (complex -1 -2))) 182 | (is (gc/= (ga/* (complex -3 -7) (complex 1 2)) (complex 11 -13))) 183 | (is (gc/= (ga/* (complex 1 2) (complex -3 -7)) (complex 11 -13))) 184 | (is (gc/= (ga/* (complex -3 -7) (complex -3 -7)) (complex -40 42))) 185 | (is (gc/= (ga/* (complex -3 -7) 3) (complex -9 -21))) 186 | (is (gc/= (ga/* 3 (complex -3 -7)) (complex -9 -21))) 187 | (is (gc/= (ga/* (complex -3 -7) -1) (complex 3 7))) 188 | (is (gc/= (ga/* -1 (complex -3 -7)) (complex 3 7))) 189 | (is (gc/= (ga/* 3 (complex 1 2)) (complex 3 6))) 190 | (is (gc/= (ga/* (complex 1 2) 3) (complex 3 6))) 191 | (is (gc/= (ga/* 3 (complex -3 -7)) (complex -9 -21))) 192 | (is (gc/= (ga/* (complex -3 -7) 3) (complex -9 -21))) 193 | (is (gc/= (ga/* -1 (complex 1 2)) (complex -1 -2))) 194 | (is (gc/= (ga/* (complex 1 2) -1) (complex -1 -2))) 195 | (is (gc/= (ga/* -1 (complex -3 -7)) (complex 3 7))) 196 | (is (gc/= (ga/* (complex -3 -7) -1) (complex 3 7)))) 197 | 198 | (let [div (ga/qsym ga /)] 199 | (deftest complex-division 200 | (is (gc/= (div (complex 1 2) (complex 1 2)) 1)) 201 | (is (gc/= (div (complex 1 2) (complex -3 -7)) (complex -17/58 1/58))) 202 | (is (gc/= (div (complex -3 -7) (complex 1 2)) (complex -17/5 -1/5))) 203 | (is (gc/= (div (complex 1 2) 3) (complex 1/3 2/3))) 204 | (is (gc/= (div 3 (complex 1 2)) (complex 3/5 -6/5))) 205 | (is (gc/= (div (complex 1 2) -1) (complex -1 -2))) 206 | (is (gc/= (div -1 (complex 1 2)) (complex -1/5 2/5))) 207 | (is (gc/= (div (complex -3 -7) (complex 1 2)) (complex -17/5 -1/5))) 208 | (is (gc/= (div (complex 1 2) (complex -3 -7)) (complex -17/58 1/58))) 209 | (is (gc/= (div (complex -3 -7) (complex -3 -7)) 1)) 210 | (is (gc/= (div (complex -3 -7) 3) (complex -1 -7/3))) 211 | (is (gc/= (div 3 (complex -3 -7)) (complex -9/58 21/58))) 212 | (is (gc/= (div (complex -3 -7) -1) (complex 3 7))) 213 | (is (gc/= (div -1 (complex -3 -7)) (complex 3/58 -7/58))) 214 | (is (gc/= (div 3 (complex 1 2)) (complex 3/5 -6/5))) 215 | (is (gc/= (div (complex 1 2) 3) (complex 1/3 2/3))) 216 | (is (gc/= (div 3 (complex -3 -7)) (complex -9/58 21/58))) 217 | (is (gc/= (div (complex -3 -7) 3) (complex -1 -7/3))) 218 | (is (gc/= (div -1 (complex 1 2)) (complex -1/5 2/5))) 219 | (is (gc/= (div (complex 1 2) -1) (complex -1 -2))) 220 | (is (gc/= (div -1 (complex -3 -7)) (complex 3/58 -7/58))) 221 | (is (gc/= (div (complex -3 -7) -1) (complex 3 7))))) 222 | 223 | (deftest complex-conjugate 224 | (is (gc/= (gmf/conjugate (complex 1 2)) (complex 1 -2))) 225 | (is (gc/= (gmf/conjugate (complex -3 -7)) (complex -3 7))) 226 | (is (gc/= (gmf/conjugate (complex 0 -2)) (complex 0 2))) 227 | (is (gc/= (gmf/conjugate (complex 0 5)) (complex 0 -5)))) 228 | 229 | (deftest complex-abs 230 | (doseq [c [(complex 1 2) (complex -2 3) (complex 4 -2) 231 | (complex -3 -7) (complex 0 -2) (complex 0 5)]] 232 | (is (gmf/approx= (ga/* c (gmf/conjugate c)) 233 | (gmf/sqr (gmf/abs c)) 234 | 1e-14)))) 235 | 236 | (deftest complex-sqrt 237 | (doseq [c [(complex 1 2) (complex -2 3) (complex 4 -2) 238 | (complex -3 -7) (complex 0 -2) (complex 0 5)]] 239 | (let [r (gmf/sqrt c)] 240 | (is (gmf/approx= c (gmf/sqr r) 1e-14)) 241 | (is (>= (real r) 0))))) 242 | 243 | (deftest complex-exp 244 | (is (gmf/approx= (gmf/exp (complex 1 2)) 245 | (complex -1.1312043837568135 2.4717266720048188) 246 | 1e-14)) 247 | (is (gmf/approx= (gmf/exp (complex 2 3)) 248 | (complex -7.3151100949011028 1.0427436562359045) 249 | 1e-14)) 250 | (is (gmf/approx= (gmf/exp (complex 4 -2)) 251 | (complex -22.720847417619233 -49.645957334580565) 252 | 1e-14)) 253 | (is (gmf/approx= (gmf/exp (complex 3 -7)) 254 | (complex 15.142531566086868 -13.195928586605717) 255 | 1e-14)) 256 | (is (gmf/approx= (gmf/exp (complex 0 -2)) 257 | (complex -0.41614683654714241 -0.90929742682568171) 258 | 1e-14)) 259 | (is (gmf/approx= (gmf/exp (complex 0 5)) 260 | (complex 0.2836621854632263 -0.95892427466313845) 261 | 1e-14))) 262 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/algo/generic/test_functor.clj: -------------------------------------------------------------------------------- 1 | ;; Test routines for clojure.algo.generic.collection 2 | 3 | ;; Copyright (c) Konrad Hinsen, 2011. All rights reserved. The use 4 | ;; and distribution terms for this software are covered by the Eclipse 5 | ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 6 | ;; which can be found in the file epl-v10.html at the root of this 7 | ;; distribution. By using this software in any fashion, you are 8 | ;; agreeing to be bound by the terms of this license. You must not 9 | ;; remove this notice, or any other, from this software. 10 | 11 | (ns clojure.algo.generic.test-functor 12 | (:use [clojure.test :only (deftest is are run-tests)]) 13 | (:require [clojure.algo.generic.functor :as gf]) 14 | (:require [clojure.algo.generic.collection :as gc])) 15 | 16 | ; Test implementations for CLojure's built-in collections 17 | (deftest builtin-collections 18 | (are [a b] (= a b) 19 | (gf/fmap inc (list 1 2 3)) (list 2 3 4) 20 | (gf/fmap inc [1 2 3]) [2 3 4] 21 | (gf/fmap inc {:A 1 :B 2 :C 3}) {:A 2 :B 3 :C 4} 22 | (gf/fmap inc #{1 2 3}) #{2 3 4} 23 | (gf/fmap inc (lazy-seq [1 2 3])) (list 2 3 4) 24 | (gf/fmap inc (seq [1 2 3])) (list 2 3 4) 25 | (gf/fmap inc (range 3)) (list 1 2 3) 26 | (gf/fmap inc nil) nil)) 27 | 28 | ; Test implementation for functions 29 | (deftest functions 30 | (let [f (fn [x] (+ x x)) 31 | x [-1 0 1 2]] 32 | (is (= (map (gf/fmap - f) x) 33 | (map (comp - f) x))))) 34 | 35 | ; Futures and delays 36 | (deftest future-test 37 | (is (= 2 @(gf/fmap inc (future 1))))) 38 | 39 | (deftest delay-test 40 | (is (= 2 @(gf/fmap inc (delay 1))))) 41 | 42 | ; Define a multiset class. The representation is a map from values to counts. 43 | (defrecord multiset [map]) 44 | 45 | (defn mset 46 | [& elements] 47 | (gc/into (new multiset {}) elements)) 48 | 49 | ; Implement the collection multimethods. 50 | (defmethod gc/conj multiset 51 | ([ms x] 52 | (let [msmap (:map ms)] 53 | (new multiset (assoc msmap x (inc (get msmap x 0)))))) 54 | ([ms x & xs] 55 | (reduce gc/conj (gc/conj ms x) xs))) 56 | 57 | (defmethod gc/empty multiset 58 | [ms] 59 | (new multiset {})) 60 | 61 | (defmethod gc/seq multiset 62 | [ms] 63 | (apply concat (map (fn [[x n]] (repeat n x)) (:map ms)))) 64 | 65 | ; Implement fmap 66 | (defmethod gf/fmap multiset 67 | [f m] 68 | (gc/into (gc/empty m) (map f (gc/seq m)))) 69 | 70 | ; Multiset tests 71 | (deftest multiset-tests 72 | (are [a b] (= a b) 73 | (gf/fmap inc (mset 1 2 3)) (mset 2 3 4))) 74 | 75 | --------------------------------------------------------------------------------