diff --git a/.Rbuildignore b/.Rbuildignore index 7e8674f..66c4508 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,2 +1,8 @@ ^gravitree\.Rproj$ ^\.Rproj\.user$ +^_pkgdown\.yml$ +^docs$ +^pkgdown$ +^\.github$ +^sandbox$ +^LICENSE\.md$ diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..0f2fe08 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,52 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: R-CMD-check + +permissions: read-all + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml new file mode 100644 index 0000000..c9f0165 --- /dev/null +++ b/.github/workflows/pkgdown.yaml @@ -0,0 +1,50 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: + +name: pkgdown + +permissions: read-all + +jobs: + pkgdown: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website + + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml new file mode 100644 index 0000000..fefc52e --- /dev/null +++ b/.github/workflows/test-coverage.yaml @@ -0,0 +1,61 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: test-coverage + +permissions: read-all + +jobs: + test-coverage: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr, any::xml2 + needs: coverage + + - name: Test coverage + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + covr::to_cobertura(cov) + shell: Rscript {0} + + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/.gitignore b/.gitignore index accfb7b..c87bf3f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ .httr-oauth .DS_Store .quarto +docs +sandbox \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 34b06d8..b395f33 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,14 +1,23 @@ Package: gravitree Title: What the Package Does (One Line, Title Case) -Version: 0.0.0.9000 -Authors@R: - person("First", "Last", , "first.last@example.com", role = c("aut", "cre"), - comment = c(ORCID = "YOUR-ORCID-ID")) +Version: 0.1 +Authors@R: c( + person("Simon", "Garnier", email = "garnier@njit.edu", role = c("aut", "cre"), + comment = c(ORCID = "0000-0002-3886-3974")), + person("Graham", "Jason", email = "jason.graham@scranton.edu", role = c("ctb", "cph")) + ) Description: What the package does (one paragraph). -License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a - license +License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 -URL: https://github.com/swarm-lab/gravitree +URL: https://github.com/swarm-lab/gravitree, https://swarm-lab.github.io/gravitree/ BugReports: https://github.com/swarm-lab/gravitree/issues +LinkingTo: + Rcpp, + RcppEigen +Imports: + Rcpp, + Rfast, + fastcluster, + stats diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..175443c --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,595 @@ +GNU General Public License +========================== + +_Version 3, 29 June 2007_ +_Copyright © 2007 Free Software Foundation, Inc. <>_ + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +“This License” refers to version 3 of the GNU General Public License. + +“Copyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +“The Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as “you”. “Licensees” and +“recipients” may be individuals or organizations. + +To “modify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a “modified version” of the earlier work or a +work “based on” the earlier work. + +A “covered work” means either the unmodified Program or a work based on +the Program. + +To “propagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To “convey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays “Appropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The “source code” for a work means the preferred form of the work for +making modifications to it. “Object code” means any non-source form of a +work. + +A “Standard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The “System Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A “Major Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The “Corresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to “keep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an “aggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A “User Product” is either **(1)** a “consumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, “normally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +“Installation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +“Additional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered “further +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An “entity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A “contributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's “contributor version”. + +A contributor's “essential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, “control” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a “patent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To “grant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. “Knowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is “discriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License “or any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the “copyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an “about box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a “copyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/NAMESPACE b/NAMESPACE index 6ae9268..b0a5dfd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,2 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(gravitree) +import(RcppEigen) +importFrom(Rcpp,evalCpp) +useDynLib(gravitree, .registration = TRUE) diff --git a/R/RcppExports.R b/R/RcppExports.R new file mode 100644 index 0000000..2477f17 --- /dev/null +++ b/R/RcppExports.R @@ -0,0 +1,74 @@ +# Generated by using Rcpp::compileAttributes() -> do not edit by hand +# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#' @name .wcov +#' +#' @title Weighted Covariance Matrix +#' +#' @description \code{wcov} computes the estimates of the weighted covariance +#' matrix and the weighted mean of the data. +#' +#' @param x A matrix with \eqn{m} columns and \eqn{n} rows, where each column +#' represents a different variable and each row a different observation. +#' +#' @param w A non-negative and non-zero vector of weights for each observation. +#' Its length must equal the number of rows of x. +#' +#' @return A list with two components: +#' \itemize{ +#' \item \code{center}: an estimate for the center (mean) of the data. +#' \item \code{cov}: the estimated (weighted) covariance matrix. +#' } +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @examples +#' m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +#' w <- runif(500) +#' gravitree:::.wcov(m, w) +#' +.wcov <- function(x, w) { + .Call(`_gravitree_wcov`, x, w) +} + +.eigen <- function(cov) { + .Call(`_gravitree_eigen`, cov) +} + +#' @name .Mahalanobis +#' +#' @title Mahalanobis Distance +#' +#' @description \code{Mahalanobis} computes the squared Mahalanobis distance of +#' all rows in \code{x} and the vector \eqn{\mu}{mu} = \code{center} with +#' respect to \eqn{\Sigma}{Sigma} = \code{cov}. This is (for vector \code{x}) +#' defined as \deqn{D^2 = (x - \mu)' \Sigma^{-1} (x - \mu)}{D^2 = (x - \mu)' +#' \Sigma^-1 (x - \mu)} +#' +#' @param x A matrix with \eqn{m} columns and \eqn{n} rows, where each column +#' represents a different variable and each row a different observation. +#' +#' @param center The mean vector of the distribution. +#' +#' @param cov The covariance matrix (\eqn{p \times p}{p x p}) of the +#' distribution. +#' +#' @return A matrix with 1 column and \eqn{n} rows representing the estimated +#' distance for each observation. +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @examples +#' m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +#' w <- runif(500) +#' covar <- gravitree:::.wcov(m, w) +#' gravitree:::.Mahalanobis(m, covar$center, covar$cov) +#' +.Mahalanobis <- function(x, center, cov) { + .Call(`_gravitree_Mahalanobis`, x, center, cov) +} + +.as_dist <- function(mat) { + .Call(`_gravitree_as_dist`, mat) +} + diff --git a/R/gravitree-package.R b/R/gravitree-package.R new file mode 100644 index 0000000..6c5fff2 --- /dev/null +++ b/R/gravitree-package.R @@ -0,0 +1,23 @@ +#' gravitree: ... +#' +#' The \code{gravitree} package provides... +#' +#' @author Simon Garnier +#' @author Jason Graham +#' +#' Maintainer: Simon Garnier +#' +#' @details +#' \tabular{ll}{ +#' Package: \tab gravitree\cr +#' Type: \tab Package\cr +#' Version: \tab 0.1\cr +#' Date: \tab 2024-05-03\cr +#' License: \tab GPL-3\cr +#' } +#' +#' @name gravitree +#' @import RcppEigen +#' @importFrom Rcpp evalCpp +#' @useDynLib gravitree, .registration = TRUE +"_PACKAGE" diff --git a/R/gravitree.R b/R/gravitree.R new file mode 100644 index 0000000..ee29df0 --- /dev/null +++ b/R/gravitree.R @@ -0,0 +1,70 @@ +#' @export +gravitree <- function(x, m, k = NULL, sample = 1, na_rm = FALSE) { + if (!is.matrix(x)) { + x <- as.matrix(x) + } + + nr <- nrow(x) + + if (nr <= 3) { + stop("'x' must contain at least 4 observations.") + } + + if (!is.matrix(m)) { + m <- as.matrix(m) + } + + if (nr != nrow(m)) { + stop("The length of 'm' does not equal the number of rows of 'x'.") + } + + if (na_rm) { + na_ix <- apply(x, 1, function(r) any(is.na(r))) | is.na(m) + x <- x[!na_ix, , drop = FALSE] + m <- m[!na_ix, , drop = FALSE] + } + + if (sample < 1) { + ix <- sample(1:nr, nr * sample, prob = m) + notix <- which(!(1:nr %in% ix)) + xx <- x[ix, , drop = FALSE] + mm <- m[ix, , drop = FALSE] + g <- Rfast::Tcrossprod(mm, mm) / (Rfast::Dist(xx)^ncol(xx)) + d <- .as_dist(log(1 / g)) + } else { + g <- Rfast::Tcrossprod(m, m) / (Rfast::Dist(x)^ncol(x)) + d <- .as_dist(log(1 / g)) + } + + tree <- fastcluster::hclust(d, method = "ward.D2") + + if (is.null(k)) { + k <- length(tree$height) - which.max(diff(tree$height)) + 1 + } + + cluster <- stats::cutree(tree, k) + + if (sample < 1) { + centers <- lapply(1:k, function(i) { + ix <- cluster == i + .wcov(xx[ix, , drop = FALSE], mm[ix]) + }) + tmp <- rep(NA, nr) + tmp[ix] <- cluster + tmp[notix] <- Rfast::rowMins(sapply(1:k, function(i) { + .Mahalanobis(x[notix, , drop = FALSE], centers[[i]]$center, centers[[i]]$cov) + })) + cluster <- tmp + } else { + centers <- lapply(1:k, function(i) { + ix <- cluster == i + .wcov(x[ix, , drop = FALSE], m[ix]) + }) + } + + list( + tree = tree, + cluster = cluster, + centers = centers + ) +} \ No newline at end of file diff --git a/README.md b/README.md index 3e20ee3..eaf5157 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ -# gravitree \ No newline at end of file +# gravitree + + +[![CRAN status](https://www.r-pkg.org/badges/version/gravitree)](https://CRAN.R-project.org/package=gravitree) +[![R-CMD-check](https://github.com/swarm-lab/gravitree/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/swarm-lab/gravitree/actions/workflows/R-CMD-check.yaml) +[![test-coverage](https://github.com/swarm-lab/gravitree/actions/workflows/test-coverage.yaml/badge.svg)](https://github.com/swarm-lab/gravitree/actions/workflows/test-coverage.yaml) + + +The goal of gravitree is to ... + +## Installation + +You can install the development version of gravitree from [GitHub](https://github.com/) with: + +``` r +# install.packages("devtools") +devtools::install_github("swarm-lab/gravitree") +``` + +## Example + +This is a basic example which shows you how to solve a common problem: + +``` r +library(gravitree) +## basic example code +``` + diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..e998a56 --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,4 @@ +url: https://swarm-lab.github.io/gravitree/ +template: + bootstrap: 5 + diff --git a/man/dot-Mahalanobis.Rd b/man/dot-Mahalanobis.Rd new file mode 100644 index 0000000..ac625e5 --- /dev/null +++ b/man/dot-Mahalanobis.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{.Mahalanobis} +\alias{.Mahalanobis} +\title{Mahalanobis Distance} +\usage{ +.Mahalanobis(x, center, cov) +} +\arguments{ +\item{x}{A matrix with \eqn{m} columns and \eqn{n} rows, where each column +represents a different variable and each row a different observation.} + +\item{center}{The mean vector of the distribution.} + +\item{cov}{The covariance matrix (\eqn{p \times p}{p x p}) of the +distribution.} +} +\value{ +A matrix with 1 column and \eqn{n} rows representing the estimated +distance for each observation. +} +\description{ +\code{Mahalanobis} computes the squared Mahalanobis distance of +all rows in \code{x} and the vector \eqn{\mu}{mu} = \code{center} with +respect to \eqn{\Sigma}{Sigma} = \code{cov}. This is (for vector \code{x}) +defined as \deqn{D^2 = (x - \mu)' \Sigma^{-1} (x - \mu)}{D^2 = (x - \mu)' + \Sigma^-1 (x - \mu)} +} +\examples{ +m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +w <- runif(500) +covar <- gravitree:::.wcov(m, w) +gravitree:::.Mahalanobis(m, covar$center, covar$cov) + +} +\author{ +Simon Garnier, \email{garnier@njit.edu} +} diff --git a/man/dot-wcov.Rd b/man/dot-wcov.Rd new file mode 100644 index 0000000..00eb3c3 --- /dev/null +++ b/man/dot-wcov.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{.wcov} +\alias{.wcov} +\title{Weighted Covariance Matrix} +\usage{ +.wcov(x, w) +} +\arguments{ +\item{x}{A matrix with \eqn{m} columns and \eqn{n} rows, where each column +represents a different variable and each row a different observation.} + +\item{w}{A non-negative and non-zero vector of weights for each observation. +Its length must equal the number of rows of x.} +} +\value{ +A list with two components: +\itemize{ +\item \code{center}: an estimate for the center (mean) of the data. +\item \code{cov}: the estimated (weighted) covariance matrix. +} +} +\description{ +\code{wcov} computes the estimates of the weighted covariance +matrix and the weighted mean of the data. +} +\examples{ +m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +w <- runif(500) +gravitree:::.wcov(m, w) + +} +\author{ +Simon Garnier, \email{garnier@njit.edu} +} diff --git a/man/gravitree.Rd b/man/gravitree.Rd new file mode 100644 index 0000000..b307ea8 --- /dev/null +++ b/man/gravitree.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gravitree-package.R +\docType{package} +\name{gravitree} +\alias{gravitree-package} +\alias{gravitree} +\title{gravitree: ...} +\description{ +The \code{gravitree} package provides... +} +\details{ +\tabular{ll}{ +Package: \tab gravitree\cr +Type: \tab Package\cr +Version: \tab 0.1\cr +Date: \tab 2024-05-03\cr +License: \tab GPL-3\cr +} +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/swarm-lab/gravitree} + \item \url{https://swarm-lab.github.io/gravitree/} + \item Report bugs at \url{https://github.com/swarm-lab/gravitree/issues} +} + +} +\author{ +Simon Garnier \href{mailto:garnier@njit.edu}{garnier@njit.edu} + +Jason Graham \href{mailto:jason.graham@scranton.edu}{jason.graham@scranton.edu} + +Maintainer: Simon Garnier \href{mailto:garnier@njit.edu}{garnier@njit.edu} +} diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..22034c4 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +*.dll diff --git a/src/Makevars b/src/Makevars new file mode 100644 index 0000000..6868846 --- /dev/null +++ b/src/Makevars @@ -0,0 +1,8 @@ +## With Rcpp 0.11.0 and later, we no longer need to set PKG_LIBS as there is +## no user-facing library. The include path to headers is already set by R. +PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) +PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) + +## With R 3.1.0 or later, you can uncomment the following line to tell R to +## enable compilation with C++11 (or even C++14) where available +#CXX_STD = CXX11 diff --git a/src/Makevars.win b/src/Makevars.win new file mode 100644 index 0000000..6868846 --- /dev/null +++ b/src/Makevars.win @@ -0,0 +1,8 @@ +## With Rcpp 0.11.0 and later, we no longer need to set PKG_LIBS as there is +## no user-facing library. The include path to headers is already set by R. +PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) +PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) + +## With R 3.1.0 or later, you can uncomment the following line to tell R to +## enable compilation with C++11 (or even C++14) where available +#CXX_STD = CXX11 diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp new file mode 100644 index 0000000..819a564 --- /dev/null +++ b/src/RcppExports.cpp @@ -0,0 +1,73 @@ +// Generated by using Rcpp::compileAttributes() -> do not edit by hand +// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#include +#include + +using namespace Rcpp; + +#ifdef RCPP_USE_GLOBAL_ROSTREAM +Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); +Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); +#endif + +// wcov +Rcpp::List wcov(Eigen::MatrixXd& x, Eigen::VectorXd& w); +RcppExport SEXP _gravitree_wcov(SEXP xSEXP, SEXP wSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Eigen::MatrixXd& >::type x(xSEXP); + Rcpp::traits::input_parameter< Eigen::VectorXd& >::type w(wSEXP); + rcpp_result_gen = Rcpp::wrap(wcov(x, w)); + return rcpp_result_gen; +END_RCPP +} +// eigen +Rcpp::List eigen(Eigen::MatrixXd& cov); +RcppExport SEXP _gravitree_eigen(SEXP covSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Eigen::MatrixXd& >::type cov(covSEXP); + rcpp_result_gen = Rcpp::wrap(eigen(cov)); + return rcpp_result_gen; +END_RCPP +} +// Mahalanobis +Eigen::MatrixXd Mahalanobis(Eigen::MatrixXd& x, Eigen::VectorXd& center, Eigen::MatrixXd& cov); +RcppExport SEXP _gravitree_Mahalanobis(SEXP xSEXP, SEXP centerSEXP, SEXP covSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Eigen::MatrixXd& >::type x(xSEXP); + Rcpp::traits::input_parameter< Eigen::VectorXd& >::type center(centerSEXP); + Rcpp::traits::input_parameter< Eigen::MatrixXd& >::type cov(covSEXP); + rcpp_result_gen = Rcpp::wrap(Mahalanobis(x, center, cov)); + return rcpp_result_gen; +END_RCPP +} +// as_dist +Rcpp::NumericVector as_dist(const Rcpp::NumericMatrix& mat); +RcppExport SEXP _gravitree_as_dist(SEXP matSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const Rcpp::NumericMatrix& >::type mat(matSEXP); + rcpp_result_gen = Rcpp::wrap(as_dist(mat)); + return rcpp_result_gen; +END_RCPP +} + +static const R_CallMethodDef CallEntries[] = { + {"_gravitree_wcov", (DL_FUNC) &_gravitree_wcov, 2}, + {"_gravitree_eigen", (DL_FUNC) &_gravitree_eigen, 1}, + {"_gravitree_Mahalanobis", (DL_FUNC) &_gravitree_Mahalanobis, 3}, + {"_gravitree_as_dist", (DL_FUNC) &_gravitree_as_dist, 1}, + {NULL, NULL, 0} +}; + +RcppExport void R_init_gravitree(DllInfo *dll) { + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); +} diff --git a/src/fast.cpp b/src/fast.cpp new file mode 100644 index 0000000..bdf6824 --- /dev/null +++ b/src/fast.cpp @@ -0,0 +1,119 @@ +#include +// [[Rcpp::depends(RcppEigen)]] + +//' @name .wcov +//' +//' @title Weighted Covariance Matrix +//' +//' @description \code{wcov} computes the estimates of the weighted covariance +//' matrix and the weighted mean of the data. +//' +//' @param x A matrix with \eqn{m} columns and \eqn{n} rows, where each column +//' represents a different variable and each row a different observation. +//' +//' @param w A non-negative and non-zero vector of weights for each observation. +//' Its length must equal the number of rows of x. +//' +//' @return A list with two components: +//' \itemize{ +//' \item \code{center}: an estimate for the center (mean) of the data. +//' \item \code{cov}: the estimated (weighted) covariance matrix. +//' } +//' +//' @author Simon Garnier, \email{garnier@@njit.edu} +//' +//' @examples +//' m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +//' w <- runif(500) +//' gravitree:::.wcov(m, w) +//' +// [[Rcpp::export(.wcov)]] +Rcpp::List wcov(Eigen::MatrixXd &x, Eigen::VectorXd &w) +{ + Eigen::VectorXd center(x.cols()); + double ws = w.sum(); + for (int i = 0; i < x.cols(); i++) + { + center(i) = (x.col(i).array() * w.array()).sum() / ws; + } + + int p = x.cols(); + Eigen::VectorXd sqw = (w.array() / ws).cwiseSqrt(); + Eigen::MatrixXd X = x.array().rowwise() - center.transpose().array(); + Eigen::MatrixXd cov = Eigen::MatrixXd(p, p).setZero().selfadjointView().rankUpdate(X.transpose() * sqw.asDiagonal()); + + return Rcpp::List::create( + Rcpp::_["center"] = center, + Rcpp::_["cov"] = cov); +} + +// [[Rcpp::export(.eigen)]] +Rcpp::List eigen(Eigen::MatrixXd &cov) +{ + Eigen::SelfAdjointEigenSolver eigensolver(cov); + + return Rcpp::List::create( + Rcpp::_["values"] = eigensolver.eigenvalues().reverse().real(), + Rcpp::_["vectors"] = -eigensolver.eigenvectors().colwise().reverse().transpose().real()); +} + +//' @name .Mahalanobis +//' +//' @title Mahalanobis Distance +//' +//' @description \code{Mahalanobis} computes the squared Mahalanobis distance of +//' all rows in \code{x} and the vector \eqn{\mu}{mu} = \code{center} with +//' respect to \eqn{\Sigma}{Sigma} = \code{cov}. This is (for vector \code{x}) +//' defined as \deqn{D^2 = (x - \mu)' \Sigma^{-1} (x - \mu)}{D^2 = (x - \mu)' +//' \Sigma^-1 (x - \mu)} +//' +//' @param x A matrix with \eqn{m} columns and \eqn{n} rows, where each column +//' represents a different variable and each row a different observation. +//' +//' @param center The mean vector of the distribution. +//' +//' @param cov The covariance matrix (\eqn{p \times p}{p x p}) of the +//' distribution. +//' +//' @return A matrix with 1 column and \eqn{n} rows representing the estimated +//' distance for each observation. +//' +//' @author Simon Garnier, \email{garnier@@njit.edu} +//' +//' @examples +//' m <- matrix(c(rnorm(500, 6), rnorm(500, 11, 3)), ncol = 2) +//' w <- runif(500) +//' covar <- gravitree:::.wcov(m, w) +//' gravitree:::.Mahalanobis(m, covar$center, covar$cov) +//' +// [[Rcpp::export(.Mahalanobis)]] +Eigen::MatrixXd Mahalanobis(Eigen::MatrixXd &x, Eigen::VectorXd ¢er, + Eigen::MatrixXd &cov) +{ + Eigen::MatrixXd cx = x.rowwise() - center.transpose(); + Eigen::MatrixXd out = (cx * cov.inverse()).array() * cx.array(); + return out.rowwise().sum(); +} + +// [[Rcpp::export(.as_dist)]] +Rcpp::NumericVector as_dist(const Rcpp::NumericMatrix& mat) { + int nrow = mat.nrow(); + int ncol = mat.ncol(); + int size = nrow * (nrow - 1) / 2; + Rcpp::NumericVector out(size); + + if (nrow > 1) { + int k = 0; + for (int j = 0; j < ncol; j++) { + for (int i = j + 1; i < nrow; i++) { + out[k++] = mat(i,j); + } + } + } + + out.attr("Size") = nrow; + out.attr("class") = "dist"; + out.attr("Diag") = false; + out.attr("Upper") = false; + return out; +} \ No newline at end of file