Math-PlanePath-113/ 0002755 0001750 0001750 00000000000 12255673734 011717 5 ustar gg gg Math-PlanePath-113/COPYING 0000644 0001750 0001750 00000104374 10641206144 012741 0 ustar gg gg
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 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
.
Math-PlanePath-113/tools/ 0002755 0001750 0001750 00000000000 12255673733 013056 5 ustar gg gg Math-PlanePath-113/tools/alternate-paper-dxdy.pl 0000644 0001750 0001750 00000004070 12022542003 017415 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl alternate-paper-dxdy.pl
#
use 5.010;
use strict;
# uncomment this to run the ### lines
#use Smart::Comments;
{
my @pending_state;
foreach my $rot (0,1,2,3) {
foreach my $oddpos (0,1) {
push @pending_state, make_state (bit => 0,
lowerbit => 0,
rot => $rot,
oddpos => $oddpos,
nextturn => 0);
}
}
my $count = 0;
my @seen_state;
my $depth = 1;
foreach my $state (@pending_state) {
$seen_state[$state] = $depth;
}
while (@pending_state) {
my @new_pending_state;
foreach my $state (@pending_state) {
$count++;
### consider state: $state
foreach my $bit (0 .. 1) {
my $next_state = $next_state[$state+$bit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @new_pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
@pending_state = @new_pending_state;
}
for (my $state = 0; $state < @next_state; $state += 2) {
$seen_state[$state] ||= '-';
my $state_string = state_string($state);
print "# used state $state depth $seen_state[$state] $state_string\n";
}
print "used state count $count\n";
}
exit 0;
Math-PlanePath-113/tools/dragon-curve-table.pl 0000644 0001750 0001750 00000014633 12021026530 017053 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl dragon-curve-table.pl
#
# Print the state tables used for DragonCurve n_to_xy().
use 5.010;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15
|| ($entry_width >= 3 && ($i % 4) == 3)) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @digit_to_dxdy;
sub make_state {
my %param = @_;
my $state = 0;
$state <<= 1; $state |= delete $param{'rev'};
$state <<= 2; $state |= delete $param{'rot'};
$state <<= 2; $state |= delete $param{'digit'};
return $state;
}
sub state_string {
my ($state) = @_;
my $digit = $state & 3; $state >>= 2;
my $rot = $state & 3; $state >>= 2;
my $rev = $state & 1; $state >>= 1;
return "rot=$rot rev=$rev (digit=$digit)";
}
foreach my $rot (0 .. 3) {
foreach my $rev (0, 1) {
foreach my $digit (0, 1, 2, 3) {
my $state = make_state (rot => $rot, rev => $rev, digit => $digit);
my $new_rev;
my $new_rot = $rot;
my $x;
my $y;
if ($rev) {
#
# 2<--3
# ^ |
# | v
# 0<--1 *
#
if ($digit == 0) {
$x = 0;
$y = 0;
$new_rev = 0;
} elsif ($digit == 1) {
$x = 1;
$y = 0;
$new_rev = 1;
$new_rot++;
} elsif ($digit == 2) {
$x = 1;
$y = 1;
$new_rev = 0;
} elsif ($digit == 3) {
$x = 2;
$y = 1;
$new_rev = 1;
$new_rot--;
}
} else {
#
# 0 3<--*
# | ^
# v |
# 1<--2
#
if ($digit == 0) {
$x = 0;
$y = 0;
$new_rev = 0;
$new_rot--;
} elsif ($digit == 1) {
$x = 0;
$y = -1;
$new_rev = 1;
} elsif ($digit == 2) {
$x = 1;
$y = -1;
$new_rev = 0;
$new_rot++;
} elsif ($digit == 3) {
$x = 1;
$y = 0;
$new_rev = 1;
}
}
$new_rot &= 3;
my $dx = 1;
my $dy = 0;
if ($rot & 2) {
$x = -$x;
$y = -$y;
$dx = -$dx;
$dy = -$dy;
}
if ($rot & 1) {
($x,$y) = (-$y,$x); # rotate +90
($dx,$dy) = (-$dy,$dx); # rotate +90
}
### rot to: "$x, $y"
my $next_dx = $x;
my $next_dy = $y;
$digit_to_x[$state] = $x;
$digit_to_y[$state] = $y;
if ($digit == 0) {
$digit_to_dxdy[$state] = $dx;
$digit_to_dxdy[$state+1] = $dy;
}
my $next_state = make_state
(rot => $new_rot,
rev => $new_rev,
digit => 0);
$next_state[$state] = $next_state;
}
}
}
### @next_state
### next_state length: 4*(4*2*2 + 4*2)
print "# next_state length ", scalar(@next_state), "\n";
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("digit_to_dxdy", \@digit_to_dxdy);
print "\n";
# {
# DIGIT: foreach my $digit (0 .. 3) {
# foreach my $rot (0 .. 3) {
# foreach my $rev (0 .. 1) {
# if ($digit_to_x[make_state(rot => $rot,
# rev => $rev,
# digit => $digit)]
# != $digit_to_dxdy[make_state(rot => $rot,
# rev => $rev,
# digit => 0)]) {
# print "digit=$digit dx different at rot=$rot rev=$rev\n";
# next DIGIT;
# }
# }
# }
# print "digit=$digit digit_to_x[] is dx\n";
# }
# }
{
my @pending_state = (0, 4, 8, 12); # in 4 arm directions
my $count = 0;
my @seen_state;
my $depth = 1;
foreach my $state (@pending_state) {
$seen_state[$state] = $depth;
}
while (@pending_state) {
my @new_pending_state;
foreach my $state (@pending_state) {
$count++;
### consider state: $state
foreach my $digit (0 .. 1) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @new_pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
@pending_state = @new_pending_state;
}
for (my $state = 0; $state < @next_state; $state += 2) {
$seen_state[$state] ||= '-';
my $state_string = state_string($state);
print "# used state $state depth $seen_state[$state] $state_string\n";
}
print "used state count $count\n";
}
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
foreach my $int (0 .. 16) {
### $int
my @digits = digit_split_lowtohigh($int,4);
my $len = 2 ** $#digits;
my $state = (scalar(@digits) & 3) << 2;
### @digits
### $len
### initial state: $state.' '.state_string($state)
my $x = 0;
my $y = 0;
foreach my $i (reverse 0 .. $#digits) {
### at: "i=$i len=$len digit=$digits[$i] state=$state ".state_string($state)
$state += $digits[$i];
### digit x: $digit_to_x[$state]
### digit y: $digit_to_y[$state]
$x += $len * $digit_to_x[$state];
$y += $len * $digit_to_y[$state];
$state = $next_state[$state];
$len /= 2;
}
### $x
### $y
print "$int $x $y\n";
}
exit 0;
__END__
Math-PlanePath-113/tools/hilbert-spiral-table.pl 0000644 0001750 0001750 00000016274 11666767377 017446 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%s", ($aref->[$i]//'undef');
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, ($aref->[$i]//'undef');
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 12) == 11) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub make_state {
my ($rot, $transpose, $spiral) = @_;
$transpose %= 2;
$rot %= 2;
$spiral %= 2;
return 4*($rot + 2*$transpose + 4*$spiral);
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;
my @min_digit;
my @max_digit;
foreach my $spiral (0,1) {
foreach my $rot (0, 1) {
foreach my $transpose (0, ($spiral ? () : (1))) {
my $state = make_state ($rot, $transpose, $spiral);
# range 0 [X,_]
# range 1 [X,X]
# range 2 [_,X]
foreach my $xrange (0,1,2) {
foreach my $yrange (0,1,2) {
my $xr = $xrange;
my $yr = $yrange;
my $bits = $xr + 3*$yr; # before rot+transpose
if ($rot) {
$xr = 2-$xr;
$yr = 2-$yr;
}
if ($transpose) {
($xr,$yr) = ($yr,$xr);
}
my ($min_digit, $max_digit);
# 3--2
# |
# 0--1
if ($xr == 0) {
# 0 or 3
if ($yr == 0) {
# x,y both low, 0 only
$min_digit = 0;
$max_digit = 0;
} elsif ($yr == 1) {
# y either, 0 or 3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 3 only
$min_digit = 3;
$max_digit = 3;
}
} elsif ($xr == 1) {
# x either, any 0,1,2,3
if ($yr == 0) {
# y low, 0 or 1
$min_digit = 0;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 0,1,2,3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 2,3 only
$min_digit = 2;
$max_digit = 3;
}
} else {
# x high, 1 or 2
if ($yr == 0) {
# y low, 1 only
$min_digit = 1;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 1 or 2
$min_digit = 1;
$max_digit = 2;
} elsif ($yr == 2) {
# y high, 2 only
$min_digit = 2;
$max_digit = 2;
}
}
### range store: $state+$bits
my $key = 3*$state + $bits;
if (defined $min_digit[$key]) {
# die "oops min_digit[] already: state=$state bits=$bits value=$min_digit[$state+$bits], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
foreach my $orig_digit (0, 1, 2, 3) {
my $digit = $orig_digit;
my $xo = 0;
my $yo = 0;
my $new_transpose = $transpose;
my $new_rot = $rot;
my $new_spiral;
# 3--2
# |
# 0--1
if ($digit == 0) {
if ($spiral) {
$new_spiral = 1;
$new_rot ^= 1;
} else {
$new_transpose ^= 1;
$new_spiral = 0;
}
} elsif ($digit == 1) {
$xo = 1;
$new_spiral = 0;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_spiral = 0;
} elsif ($digit == 3) {
$yo = 1;
$new_transpose ^= 1;
$new_rot ^= 1;
$new_spiral = 0;
}
### base: "$xo, $yo"
if ($transpose) {
($xo,$yo) = ($yo,$xo);
}
### transp to: "$xo, $yo"
if ($rot) {
$xo ^= 1;
$yo ^= 1;
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$xy_to_digit[$state + $xo*2+$yo] = $orig_digit;
my $next_state = make_state
($new_rot, $new_transpose, $new_spiral);
$next_state[$state+$orig_digit] = $next_state;
}
}
}
}
### @next_state
### @digit_to_x
### @digit_to_y
### next_state length: 4*(4*2*2 + 4*2)
### next_state length: scalar(@next_state)
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("xy_to_digit", \@xy_to_digit);
print_table12 ("min_digit", \@min_digit);
print_table12 ("max_digit", \@max_digit);
my $spiral_rot_state = make_state (1, # rot
0, # transpose
1); # spiral
print "# neg state $spiral_rot_state\n";
print "\n";
exit 0;
__END__
my $x_cmp = $x_max + $len;
my $y_cmp = $y_max + $len;
my $digit = $min_digit[4*$min_state + ($x1 >= $x_cmp) + 2*($x2 >= $x_cmp)
+ ($y1 >= $y_cmp) + 2*($y2 >= $y_cmp)];
$min_state += $digit;
$n_lo += $digit * $power;
if ($digit_to_x[$min_state]) { $x_min += $len; }
if ($digit_to_y[$min_state]) { $x_min += $len; }
$min_state = $next_state[$min_state + $min_digit];
Math-PlanePath-113/tools/dekking-curve-table.pl 0000644 0001750 0001750 00000015435 12021305065 017221 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'max';
use Math::PlanePath::DekkingCentres;
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined $_ ? length : 5} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if ($entry_width >= 2 && ($i % 25) == 4) {
print " # ".($i-4);
}
if (($i % 25) == 24
|| $entry_width >= 2 && ($i % 5) == 4) {
print "\n ".(" " x length($name));
} elsif (($i % 5) == 4) {
print " ";
}
}
}
}
sub make_state {
my ($rev, $rot) = @_;
$rev %= 2;
$rot %= 4;
return 25*($rot + 4*$rev);
}
my @next_state;
my @edge_dx;
my @edge_dy;
my @yx_to_digit;
foreach my $rev (0, 1) {
foreach my $rot (0, 1, 2, 3) {
foreach my $orig_digit (0 .. 24) {
my $digit = $orig_digit;
if ($rev) {
$digit = 25-$digit;
}
my $xo;
my $yo;
my $new_rot = $rot;
my $new_rev = $rev;
if ($digit == 0) {
$xo = 0;
$yo = 0;
} elsif ($digit == 1) {
$xo = 1;
$yo = 0;
} elsif ($digit == 2) {
$xo = 2;
$yo = 0;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 3) {
$xo = 2;
$yo = 1;
$new_rev ^= 1;
} elsif ($digit == 4) {
$xo = 1;
$yo = 1;
$new_rot = $rot + 1;
} elsif ($digit == 5) {
$xo = 1;
$yo = 2;
} elsif ($digit == 6) {
$xo = 2;
$yo = 2;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 7) {
$xo = 2;
$yo = 3;
$new_rev ^= 1;
} elsif ($digit == 8) {
$xo = 1;
$yo = 3;
$new_rot = $rot + 2;
} elsif ($digit == 9) {
$xo = 0;
$yo = 3;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 10) {
$xo = 0;
$yo = 4;
} elsif ($digit == 11) {
$xo = 1;
$yo = 4;
} elsif ($digit == 12) {
$xo = 2;
$yo = 4;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 13) {
$xo = 3;
$yo = 4;
$new_rot = $rot + 1;
} elsif ($digit == 14) {
$xo = 3;
$yo = 5;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 15) {
$xo = 4;
$yo = 5;
$new_rot = $rot - 1;
} elsif ($digit == 16) {
$xo = 4;
$yo = 4;
$new_rot = $rot - 1;
} elsif ($digit == 17) {
$xo = 4;
$yo = 3;
$new_rev ^= 1;
} elsif ($digit == 18) {
$xo = 3;
$yo = 3;
$new_rot = $rot - 1;
} elsif ($digit == 19) {
$xo = 3;
$yo = 2;
$new_rot = $rot + 1;
$new_rev ^= 1;
} elsif ($digit == 20) {
$xo = 3;
$yo = 1;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 21) {
$xo = 4;
$yo = 1;
$new_rot = $rot + 1;
} elsif ($digit == 22) {
$xo = 4;
$yo = 2;
} elsif ($digit == 23) {
$xo = 5;
$yo = 2;
$new_rot = $rot + 1;
$new_rev ^= 1;
} elsif ($digit == 24) {
$xo = 5;
$yo = 1;
$new_rot = $rot + 1;
$new_rev ^= 1;
} elsif ($digit == 25) {
$xo = 5;
$yo = 0;
$new_rot = $rot + 1;
} else {
die;
}
### base: "$xo, $yo"
my $state = make_state ($rev, $rot);
my $shift_xo = $xo;
my $shift_yo = $yo;
if ($rot & 2) {
$shift_xo = 5 - $shift_xo;
$shift_yo = 5 - $shift_yo;
}
if ($rot & 1) {
($shift_xo,$shift_yo) = (5-$shift_yo,$shift_xo);
}
$yx_to_digit[$state + $shift_yo*5 + $shift_xo] = $orig_digit;
# if ($rev) {
# if (($rot % 4) == 0) {
# } elsif (($rot % 4) == 1) {
# $yo -= 1;
# } elsif (($rot % 4) == 2) {
# $yo -= 1;
# $xo -= 1;
# } elsif (($rot % 4) == 3) {
# $xo -= 1;
# }
# } else {
# if (($rot % 4) == 0) {
# } elsif (($rot % 4) == 1) {
# $yo -= 1;
# } elsif (($rot % 4) == 2) {
# $yo -= 1;
# $xo -= 1;
# } elsif (($rot % 4) == 3) {
# $xo -= 1;
# }
# # $xo -= 1;
# }
if ($rot & 2) {
$xo = 5 - $xo;
$yo = 5 - $yo;
}
if ($rot & 1) {
($xo,$yo) = (5-$yo,$xo);
}
### rot to: "$xo, $yo"
$edge_dx[$state+$orig_digit] = $xo - $Math::PlanePath::DekkingCentres::_digit_to_x[$state+$orig_digit];
$edge_dy[$state+$orig_digit] = $yo - $Math::PlanePath::DekkingCentres::_digit_to_y[$state+$orig_digit];
my $next_state = make_state ($new_rev, $new_rot);
$next_state[$state+$orig_digit] = $next_state;
}
}
}
print "# state length ",scalar(@next_state)," in each of 4 tables\n";
# print_table ("next_state", \@next_state);
print_table ("edge_dx", \@edge_dx);
print_table ("edge_dy", \@edge_dy);
# print_table ("last_yx_to_digit", \@yx_to_digit);
### @next_state
### @edge_dx
### @edge_dy
### @yx_to_digit
### next_state length: scalar(@next_state)
print "\n";
exit 0;
Math-PlanePath-113/tools/beta-omega-table.pl 0000644 0001750 0001750 00000027037 12161517122 016471 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl beta-omega-table.pl
#
# Print the state tables used in BetaOmega.pm.
#
# This isn't a thing of beauty. A state incorporates the beta vs omega
# shape and the orientation of that shape as 4 rotations by 90-degrees, a
# transpose swapping X,Y, and a reversal for numbering points the opposite
# way around.
#
# The reversal is only needed for the beta, as noted in the
# Math::PlanePath::BetaOmega POD. For an omega the reverse is the same as
# the forward. make_state() collapses a reverse omega down to corresponding
# plain forward omega.
#
# State values are 0, 4, 8, etc. Having them 4 apart means a base 4 digit
# from N in n_to_xy() can be added state+digit to make an index into the
# tables.
#
# For @max_digit and @min_digit the input is instead 3*3=9 values, and in
# those tables the index is "state*3 + input". 3*state puts states 12
# apart, which is more than the 9 input values needs, but 3*state is a
# little less work in the code than say (state/4)*9 to change from 4-stride
# to exactly 9-stride.
#
use 5.010;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15
|| ($entry_width >= 3 && ($i % 4) == 3)) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 12) == 11) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;
my @min_digit;
my @max_digit;
sub state_string {
my ($state) = @_;
my $digit = $state % 4; $state = int($state/4);
my $transpose = $state % 2; $state = int($state/2);
my $rot = $state % 4; $state = int($state/4);
my $rev = $state % 2; $state = int($state/2);
my $omega = $state % 2; $state = int($state/2);
my $omega_str = ($omega ? 'omega' : 'beta');
return "$omega_str transpose=$transpose rot=$rot rev=$rev";
}
sub make_state {
my ($omega, $rev, $rot, $transpose, $digit) = @_;
if ($omega && $rev) {
$rev = 0;
if ($transpose) {
$rot--;
} else {
$rot++;
}
$transpose ^= 1;
}
$transpose %= 2;
$rev %= 2;
$rot %= 4;
return $digit + 4*($transpose + 2*($rot + 4*($rev + 2*$omega)));
}
foreach my $omega (0, 1) {
foreach my $rev (0, ($omega ? () : (1))) {
foreach my $rot (0, 1, 2, 3) {
foreach my $transpose (0, 1) {
my $state = make_state ($omega, $rev, $rot, $transpose, 0);
### $state
# range 0 [X,_]
# range 1 [X,X]
# range 2 [_,X]
foreach my $xrange (0,1,2) {
foreach my $yrange (0,1,2) {
my $xr = $xrange;
my $yr = $yrange;
my $bits = $xr + 3*$yr; # before transpose etc
if ($rot & 1) {
($xr,$yr) = ($yr,2-$xr);
}
if ($rot & 2) {
$xr = 2-$xr;
$yr = 2-$yr;
}
if ($transpose) {
($xr,$yr) = ($yr,$xr);
}
if ($rev) {
# 2--1
# | |
# 3 0
$xr = 2-$xr;
}
my ($min_digit, $max_digit);
# 1--2
# | |
# 0 3
if ($xr == 0) {
# 0 or 1 only
if ($yr == 0) {
# x,y both low, 0 only
$min_digit = 0;
$max_digit = 0;
} elsif ($yr == 1) {
# y either, 0 or 1
$min_digit = 0;
$max_digit = 1;
} elsif ($yr == 2) {
# y high, 1 only
$min_digit = 1;
$max_digit = 1;
}
} elsif ($xr == 1) {
# x either, any 0,1,2,3
if ($yr == 0) {
# y low, 0 or 3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 1) {
# y either, 0,1,2,3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 1,2 only
$min_digit = 1;
$max_digit = 2;
}
} else {
# x high, 2 or 3
if ($yr == 0) {
# y low, 3 only
$min_digit = 3;
$max_digit = 3;
} elsif ($yr == 1) {
# y either, 2 or 3
$min_digit = 2;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 2 only
$min_digit = 2;
$max_digit = 2;
}
}
### range store: $state+$bits
my $key = 3*$state + $bits;
if (defined $min_digit[$key]) {
die "oops min_digit[] already: state=$state bits=$bits value=$min_digit[$state+$bits], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
foreach my $orig_digit (0, 1, 2, 3) {
my $digit = $orig_digit;
if ($rev) {
$digit = 3-$digit;
}
my $xo = 0;
my $yo = 0;
my $new_transpose = $transpose;
my $new_rot = $rot;
my $new_omega = 0;
my $new_rev = $rev;
if ($omega) {
# 1---2
# | |
# --0 3--
$new_omega = 0;
if ($digit == 0) {
$new_transpose = $transpose ^ 1;
if ($transpose) {
$new_rot = $rot + 1;
} else {
$new_rot = $rot - 1;
}
} elsif ($digit == 1) {
$yo = 1;
if ($transpose) {
$new_rot = $rot - 1;
} else {
$new_rot = $rot + 1;
}
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_transpose = $transpose ^ 1;
$new_rev ^= 1;
} elsif ($digit == 3) {
$xo = 1;
$new_rot = $rot + 2;
$new_rev ^= 1;
}
} else {
# 1---2
# | |
# --0 3
# |
if ($digit == 0) {
$new_transpose = $transpose ^ 1;
if ($transpose) {
$new_rot = $rot + 1;
} else {
$new_rot = $rot - 1;
}
} elsif ($digit == 1) {
$yo = 1;
if ($transpose) {
$new_rot = $rot - 1;
} else {
$new_rot = $rot + 1;
}
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_transpose = $transpose ^ 1;
$new_rev ^= 1;
} elsif ($digit == 3) {
$xo = 1;
if ($transpose) {
$new_rot = $rot + 1;
} else {
$new_rot = $rot - 1;
}
$new_omega = 1;
}
}
### base: "$xo, $yo"
if ($transpose) {
($xo,$yo) = ($yo,$xo);
}
### transp to: "$xo, $yo"
if ($rot & 2) {
$xo ^= 1;
$yo ^= 1;
}
if ($rot & 1) {
($xo,$yo) = ($yo^1,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$xy_to_digit[$state + $xo*2+$yo] = $orig_digit;
my $next_state = make_state
($new_omega, $new_rev, $new_rot, $new_transpose, 0);
$next_state[$state+$orig_digit] = $next_state;
}
}
}
}
}
### @next_state
### @digit_to_x
### @digit_to_y
### next_state length: 4*(4*2*2 + 4*2)
### next_state length: scalar(@next_state)
my $next_state_size = scalar(@next_state);
my $state_count = $next_state_size/4;
print "# next_state table has $next_state_size entries, is $state_count states\n";
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("xy_to_digit", \@xy_to_digit);
print_table12 ("min_digit", \@min_digit);
print_table12 ("max_digit", \@max_digit);
my $invert_state = make_state (0, # omega
0, # rev
3, # rot
1, # transpose
0); # digit
### $invert_state
print "\n";
{
my @pending_state = (0);
my $count = 0;
my @seen_state;
my $depth = 0;
$seen_state[0] = $depth;
while (@pending_state) {
$depth++;
my @new_pending_state;
foreach my $state (@pending_state) {
$count++;
### consider state: $state
foreach my $digit (0 .. 3) {
my $next_state = $next_state[$state+$digit];
if (! defined $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @new_pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
}
@pending_state = @new_pending_state;
}
for (my $state = 0; $state < @next_state; $state += 4) {
print "# used state $state depth $seen_state[$state]\n";
}
print "used state count $count\n";
}
{
print "\n";
print "initial 0: ",state_string(0),"\n";
print "initial 28: ",state_string(28),"\n";
require Graph::Easy;
my $g = Graph::Easy->new;
for (my $state = 0; $state < scalar(@next_state); $state += 4) {
my $next = $next_state[$state];
$g->add_edge("$state: ".state_string($state),
"$next: ".state_string($next));
}
print $g->as_ascii();
}
exit 0;
Math-PlanePath-113/tools/pythagorean-tree.pl 0000644 0001750 0001750 00000003215 12254122473 016655 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl pythagorean-tree.pl
#
# Print tree diagrams used in the Math::PlanePath::PythagoreanTree docs.
#
use 5.010;
use strict;
use Math::PlanePath::PythagoreanTree;
foreach my $tree_type ('UAD','UArD','FB','UMT') {
my $str = <<"HERE";
tree_type => "$tree_type"
+-> 00005
+-> 00002 --+-> 00006
| +-> 00007
|
| +-> 00008
001 --+-> 00003 --+-> 00009
| +-> 00010
|
| +-> 00011
+-> 00004 --+-> 00012
+-> 00013
HERE
my $path = Math::PlanePath::PythagoreanTree->new(tree_type => $tree_type,
coordinates => 'AB');
$str =~ s{(\d+)}
{
my ($x,$y) = $path->n_to_xy($1);
my $len = length($1);
sprintf '%-*s', $len, "$x,$y";
}ge;
print $str;
}
Math-PlanePath-113/tools/hilbert-curve-table.pl 0000644 0001750 0001750 00000014713 12036160013 017232 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%d", $aref->[$i];
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 12) == 11) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub make_state {
my ($rot, $transpose) = @_;
$transpose %= 2;
$rot %= 2;
return 4*($transpose + 2*$rot);
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @yx_to_digit;
my @min_digit;
my @max_digit;
foreach my $rot (0, 1) {
foreach my $transpose (0, 1) {
my $state = make_state ($rot, $transpose);
# range 0 [X,_]
# range 1 [X,X]
# range 2 [_,X]
foreach my $xrange (0,1,2) {
foreach my $yrange (0,1,2) {
my $xr = $xrange;
my $yr = $yrange;
my $bits = $xr + 3*$yr; # before rot+transpose
if ($rot) {
$xr = 2-$xr;
$yr = 2-$yr;
}
if ($transpose) {
($xr,$yr) = ($yr,$xr);
}
my ($min_digit, $max_digit);
# 3--2
# |
# 0--1
if ($xr == 0) {
# 0 or 3
if ($yr == 0) {
# x,y both low, 0 only
$min_digit = 0;
$max_digit = 0;
} elsif ($yr == 1) {
# y either, 0 or 3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 3 only
$min_digit = 3;
$max_digit = 3;
}
} elsif ($xr == 1) {
# x either, any 0,1,2,3
if ($yr == 0) {
# y low, 0 or 1
$min_digit = 0;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 0,1,2,3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 2,3 only
$min_digit = 2;
$max_digit = 3;
}
} else {
# x high, 1 or 2
if ($yr == 0) {
# y low, 1 only
$min_digit = 1;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 1 or 2
$min_digit = 1;
$max_digit = 2;
} elsif ($yr == 2) {
# y high, 2 only
$min_digit = 2;
$max_digit = 2;
}
}
### range store: $state+$bits
my $key = 3*$state + $bits;
if (defined $min_digit[$key]) {
die "oops min_digit[] already: state=$state bits=$bits value=$min_digit[$state+$bits], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
foreach my $orig_digit (0, 1, 2, 3) {
my $digit = $orig_digit;
my $xo = 0;
my $yo = 0;
my $new_transpose = $transpose;
my $new_rot = $rot;
# 3--2
# |
# 0--1
if ($digit == 0) {
$new_transpose ^= 1;
} elsif ($digit == 1) {
$xo = 1;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
} elsif ($digit == 3) {
$yo = 1;
$new_transpose ^= 1;
$new_rot ^= 1;
}
### base: "$xo, $yo"
if ($transpose) {
($xo,$yo) = ($yo,$xo);
}
### transp to: "$xo, $yo"
if ($rot) {
$xo ^= 1;
$yo ^= 1;
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$yx_to_digit[$state + 2*$yo + $xo] = $orig_digit;
my $next_state = make_state ($new_rot, $new_transpose);
$next_state[$state+$orig_digit] = $next_state;
}
}
}
### @next_state
### @digit_to_x
### @digit_to_y
### next_state length: 4*(4*2*2 + 4*2)
### next_state length: scalar(@next_state)
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("yx_to_digit", \@yx_to_digit);
print_table12 ("min_digit", \@min_digit);
print_table12 ("max_digit", \@max_digit);
my $invert_state = make_state (1, # rot
1); # transpose
### $invert_state
print "\n";
exit 0;
__END__
my $x_cmp = $x_max + $len;
my $y_cmp = $y_max + $len;
my $digit = $min_digit[4*$min_state + ($x1 >= $x_cmp) + 2*($x2 >= $x_cmp)
+ ($y1 >= $y_cmp) + 2*($y2 >= $y_cmp)];
$min_state += $digit;
$n_lo += $digit * $power;
if ($digit_to_x[$min_state]) { $x_min += $len; }
if ($digit_to_y[$min_state]) { $x_min += $len; }
$min_state = $next_state[$min_state + $min_digit];
Math-PlanePath-113/tools/kochel-curve-table.pl 0000644 0001750 0001750 00000020264 11666767323 017075 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'min','max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined && length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print "); # ",$i-8,"\n";
} else {
print ",";
if (($i % 9) == 8) {
print " # ".($i-8);
}
if (($i % 9) == 8) {
print "\n ".(" " x length($name));
} elsif (($i % 3) == 2) {
print " ";
}
}
}
}
sub print_table36 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined && length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*d", $entry_width, $aref->[$i];
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 36) == 5) {
print " # ".($i-5);
}
if (($i % 6) == 5) {
print "\n ".(" " x length($name));
} elsif (($i % 6) == 5) {
print " ";
}
}
}
}
sub make_state {
my ($f, $rev, $rot) = @_;
$rev %= 2;
if ($f && $rev) {
$rot += 2;
$rev = 0;
}
$rot %= 4;
return 9*($rot + 4*($rev + 2*$f));
}
# x__ 0
# xx_ 1
# xxx 2
# _xx 3
# __x 4
# _x_ 5
my @r_to_cover = ([1,0,0],
[1,1,0],
[1,1,1],
[0,1,1],
[0,0,1],
[0,1,0]);
my @reverse_range = (4,3,2,1,0,5);
my @min_digit;
my @max_digit;
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;
foreach my $f (0, 1) {
foreach my $rot (0, 1, 2, 3) {
foreach my $rev (0, ($f ? () : (1))) {
my $state = make_state ($f, $rev, $rot);
foreach my $orig_digit (0 .. 8) {
my $digit = $orig_digit;
if ($rev) {
$digit = 8-$digit;
}
my $xo;
my $yo;
my $new_rot = $rot;
my $new_rev = $rev;
my $new_f;
if ($f) {
if ($digit == 0) {
$xo = 0;
$yo = 0;
$new_f = 0;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$xo = 0;
$yo = 1;
$new_f = 1;
} elsif ($digit == 2) {
$xo = 0;
$yo = 2;
$new_f = 0;
$new_rot = $rot + 1;
} elsif ($digit == 3) {
$xo = 1;
$yo = 2;
$new_rot = $rot - 1;
$new_f = 1;
} elsif ($digit == 4) {
$xo = 1;
$yo = 1;
$new_f = 1;
$new_rot = $rot + 2;
} elsif ($digit == 5) {
$xo = 1;
$yo = 0;
$new_f = 1;
$new_rot = $rot - 1;
} elsif ($digit == 6) {
$xo = 2;
$yo = 0;
$new_f = 0;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 7) {
$xo = 2;
$yo = 1;
$new_f = 1;
} elsif ($digit == 8) {
$xo = 2;
$yo = 2;
$new_f = 0;
$new_rot = $rot + 1;
} else {
die;
}
} else {
if ($digit == 0) {
$xo = 0;
$yo = 0;
$new_rev ^= 1;
$new_f = 0;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$xo = 0;
$yo = 1;
$new_f = 1;
} elsif ($digit == 2) {
$xo = 0;
$yo = 2;
$new_f = 0;
$new_rot = $rot + 1;
} elsif ($digit == 3) {
$xo = 1;
$yo = 2;
$new_rot = $rot - 1;
$new_f = 1;
} elsif ($digit == 4) {
$xo = 2;
$yo = 2;
$new_f = 0;
} elsif ($digit == 5) {
$xo = 2;
$yo = 1;
$new_f = 1;
$new_rot = $rot + 2;
} elsif ($digit == 6) {
$xo = 1;
$yo = 1;
$new_f = 0;
$new_rev ^= 1;
} elsif ($digit == 7) {
$xo = 1;
$yo = 0;
$new_f = 1;
$new_rot = $rot - 1;
} elsif ($digit == 8) {
$xo = 2;
$yo = 0;
$new_f = 0;
} else {
die;
}
}
### base: "$xo, $yo"
if ($rot & 2) {
$xo = 2 - $xo;
$yo = 2 - $yo;
}
if ($rot & 1) {
($xo,$yo) = (2-$yo,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$xy_to_digit[$state + 3*$xo + $yo] = $orig_digit;
my $next_state = make_state ($new_f, $new_rev, $new_rot);
$next_state[$state+$orig_digit] = $next_state;
}
foreach my $xrange (0 .. 5) {
foreach my $yrange (0 .. 5) {
my $xr = $xrange;
my $yr = $yrange;
my $bits = $xr + 6*$yr; # before transpose etc
my $key = 4*$state + $bits;
### assert: (4*$state % 36) == 0
my $min_digit = 8;
my $max_digit = 0;
foreach my $digit (0 .. 8) {
my $x = $digit_to_x[$state + $digit];
my $y = $digit_to_y[$state + $digit];
next unless $r_to_cover[$xr]->[$x];
next unless $r_to_cover[$yr]->[$y];
$min_digit = min($digit,$min_digit);
$max_digit = max($digit,$max_digit);
}
### min/max: "state=$state 4*state=".(4*$state)." bits=$bits key=$key"
if (defined $min_digit[$key]) {
# die "oops min_digit[] already: state=$state bits=$bits value=$min_digit[$state+$bits], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
}
}
}
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("xy_to_digit", \@xy_to_digit);
print_table36 ("min_digit", \@min_digit);
print_table36 ("max_digit", \@max_digit);
print "# state length ",scalar(@next_state)," in each of 4 tables\n\n";
print "# R reverse state ",make_state(0,1,-1),"\n";
### @next_state
### @digit_to_x
### @digit_to_y
### @xy_to_digit
### next_state length: scalar(@next_state)
{
my @pending_state = (0);
my $count = 0;
my @seen_state;
my $depth = 1;
$seen_state[0] = $depth;
while (@pending_state) {
my $state = pop @pending_state;
$count++;
### consider state: $state
foreach my $digit (0 .. 8) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
for (my $state = 0; $state < @next_state; $state += 9) {
print "# used state $state depth $seen_state[$state]\n";
}
print "used state count $count\n";
}
print "\n";
exit 0;
Math-PlanePath-113/tools/dragon-curve-dxdy.pl 0000644 0001750 0001750 00000011634 12022543023 016734 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl dragon-curve-dxdy.pl
#
# Print the state tables used for DragonCurve n_to_dxdy(). These are not
# the same as the tables for n_to_xy() which are in dragon-curve-table.pl.
use 5.010;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15
|| ($entry_width >= 3 && ($i % 4) == 3)) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
my @next_state;
my @state_to_dxdy;
sub make_state {
my %param = @_;
my $state = 0;
$state <<= 1; $state |= delete $param{'nextturn'}; # high
$state <<= 2; $state |= delete $param{'rot'};
$state <<= 1; $state |= delete $param{'prevbit'};
$state <<= 1; $state |= delete $param{'digit'}; # low
if (%param) { die; }
return $state;
}
sub state_string {
my ($state) = @_;
my $digit = $state & 1; $state >>= 1;
my $prevbit = $state & 1; $state >>= 1;
my $rot = $state & 3; $state >>= 2;
my $nextturn = $state & 1; $state >>= 1;
return "rot=$rot prevbit=$prevbit (digit=$digit)";
}
foreach my $nextturn (0, 1) {
foreach my $rot (0, 1, 2, 3) {
foreach my $prevbit (0, 1) {
my $state = make_state (nextturn => $nextturn,
rot => $rot,
prevbit => $prevbit,
digit => 0);
### $state
foreach my $bit (0, 1) {
my $new_nextturn = $nextturn;
my $new_prevbit = $bit;
my $new_rot = $rot;
if ($bit != $prevbit) { # count 0<->1 transitions
$new_rot++;
$new_rot &= 3;
}
if ($bit == 0) {
$new_nextturn = $prevbit; # bit above lowest 0
}
my $dx = 1;
my $dy = 0;
if ($rot & 2) {
$dx = -$dx;
$dy = -$dy;
}
if ($rot & 1) {
($dx,$dy) = (-$dy,$dx); # rotate +90
}
### rot to: "$dx, $dy"
my $next_dx = $dx;
my $next_dy = $dy;
if ($nextturn) {
($next_dx,$next_dy) = ($next_dy,-$next_dx); # right, rotate -90
} else {
($next_dx,$next_dy) = (-$next_dy,$next_dx); # left, rotate +90
}
my $frac_dx = $next_dx - $dx;
my $frac_dy = $next_dy - $dy;
my $masked_state = $state & 0x1C;
$state_to_dxdy[$masked_state] = $dx;
$state_to_dxdy[$masked_state + 1] = $dy;
$state_to_dxdy[$masked_state + 2] = $frac_dx;
$state_to_dxdy[$masked_state + 3] = $frac_dy;
my $next_state = make_state
(nextturn => $new_nextturn,
rot => $new_rot,
prevbit => $new_prevbit,
digit => 0);
$next_state[$state+$bit] = $next_state;
}
}
}
}
### @next_state
### @state_to_dxdy
### next_state length: 4*(4*2*2 + 4*2)
print "# next_state length ", scalar(@next_state), "\n";
print_table ("next_state", \@next_state);
print_table ("state_to_dxdy", \@state_to_dxdy);
print "\n";
{
my @pending_state = (0, 4, 8, 12); # in 4 arm directions
my $count = 0;
my @seen_state;
my $depth = 1;
foreach my $state (@pending_state) {
$seen_state[$state] = $depth;
}
while (@pending_state) {
my @new_pending_state;
foreach my $state (@pending_state) {
$count++;
### consider state: $state
foreach my $bit (0 .. 1) {
my $next_state = $next_state[$state+$bit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @new_pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
@pending_state = @new_pending_state;
}
for (my $state = 0; $state < @next_state; $state += 2) {
$seen_state[$state] ||= '-';
my $state_string = state_string($state);
print "# used state $state depth $seen_state[$state] $state_string\n";
}
print "used state count $count\n";
}
exit 0;
Math-PlanePath-113/tools/flowsnake-centres-table.pl 0000644 0001750 0001750 00000013732 12063226253 020122 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Not working
# Usage: perl flowsnake-centres-table.pl
#
# Print the state tables used for Math:PlanePath::FlowsnakeCentres n_to_xy().
use 5.010;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table14 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
my $entry_str = $aref->[$i]//'undef';
if ($i == $#$aref) {
$entry_str .= ");";
} else {
$entry_str .= ",";
}
if ($i % 14 == 0 && $#$aref > 14) {
printf "%-*s", $entry_width+1, $entry_str;
} else {
printf "%*s", $entry_width+1, $entry_str;
}
if ($i % 14 == 13) {
print " # ",$i-13,",",$i-6,"\n";
if ($i != $#$aref) {
print " ".(" " x length($name));
}
} elsif ($i % 7 == 6) {
print " ";
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
my $entry_str = $aref->[$i]//'undef';
if ($i == $#$aref) {
$entry_str .= ");";
} else {
$entry_str .= ",";
}
if ($i % 12 == 0 && $#$aref > 12) {
printf "%-*s", $entry_width+1, $entry_str;
} else {
printf "%*s", $entry_width+1, $entry_str;
}
if ($i % 12 == 11) {
print "\n";
if ($i != $#$aref) {
print " ".(" " x length($name));
}
} elsif ($i % 6 == 5) {
print " ";
}
}
}
my @next_state;
my @digit_to_i;
my @digit_to_j;
my @state_to_di;
my @state_to_dj;
sub make_state {
my %param = @_;
my $state = 0;
$state *= 6; $state += delete $param{'rot'}; # high
$state *= 2; $state += delete $param{'rev'};
$state *= 7; $state += delete $param{'digit'}; # low
if (%param) { die; }
return $state;
}
sub state_string {
my ($state) = @_;
my $digit = $state % 7; $state = int($state/7); # low
my $rev = $state % 2; $state = int($state/2);
my $rot = $state % 6; $state = int($state/6); # high
return "rot=$rot rev=$rev (digit=$digit)";
}
foreach my $rev (0, 1) {
foreach my $rot (0 .. 5) {
foreach my $digit (0 .. 6) {
my $state = make_state (rot => $rot,
rev => $rev,
digit => $digit);
my $new_rev = $rev;
my $new_rot = $rot;
my $plain_digit = ($rev ? 6-$digit : $digit);
my ($i, $j);
if ($rev) {
#
# 0 5
# ^ ^
# / / \
# 1 4 6----
# \ \
#
# 2-----3
if ($digit == 0) {
$i = 0;
$j = 0;
$new_rev = 0;
} elsif ($digit == 1) {
$i = 1;
$j = 0;
$new_rev = 1;
$new_rot += 1;
} elsif ($digit == 2) {
$i = 2;
$j = -1;
$new_rev = 1;
} elsif ($digit == 3) {
$i = 3;
$j = -1;
$new_rot += 1;
$new_rev = 1;
} elsif ($digit == 4) {
$i = 3;
$j = 0;
$new_rot += 3;
$new_rev = 0;
} elsif ($digit == 5) {
$i = 2;
$j = 0;
$new_rot += 2;
$new_rev = 0;
} elsif ($digit == 6) {
$i = 1;
$j = 1;
$new_rev = 1;
}
} else {
# 4-->5
# ^ \
# / v
# 3-->2 6<---7
# \
# v
# 0-->1
if ($digit == 0) {
$i = 0;
$j = 0;
$new_rev = 0;
} elsif ($digit == 1) {
$i = 1;
$j = 0;
$new_rev = 1;
$new_rot += 2;
} elsif ($digit == 2) {
$i = 0;
$j = 1;
$new_rev = 1;
$new_rot += 3;
} elsif ($digit == 3) {
$i = -1;
$j = 1;
$new_rev = 0;
$new_rot += 1;
} elsif ($digit == 4) {
$i = -1;
$j = 2;
$new_rev = 0;
} elsif ($digit == 5) {
$i = 0;
$j = 2;
$new_rev = 0;
$new_rot -= 1;
} elsif ($digit == 6) {
$i = 1;
$j = 1;
$new_rev = 1;
}
}
foreach (1 .. $rot) {
($i,$j) = (-$j, $i+$j); # rotate +60
}
$new_rot %= 6;
my $next_state = make_state
(rot => $new_rot,
rev => $new_rev,
digit => 0);
$next_state[$state] = $next_state;
$digit_to_i[$state] = $i;
$digit_to_j[$state] = $j;
}
my $state = make_state (rot => $rot,
rev => $rev,
digit => 0);
my $di = 1;
my $dj = 0;
foreach (1 .. $rot) {
($di,$dj) = (-$dj, $di+$dj); # rotate +60
}
$state_to_di[$state/7] = $di;
$state_to_dj[$state/7] = $dj;
}
}
### @next_state
### @digit_to_dxdy
### next_state length: 4*(4*2*2 + 4*2)
print "# next_state length ", scalar(@next_state), "\n";
print_table14 ("next_state", \@next_state);
print_table14 ("digit_to_i", \@digit_to_i);
print_table14 ("digit_to_j", \@digit_to_j);
print_table12 ("state_to_di", \@state_to_di);
print_table12 ("state_to_dj", \@state_to_dj);
print "\n";
exit 0;
Math-PlanePath-113/tools/flowsnake-table.pl 0000644 0001750 0001750 00000017173 12065504530 016463 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl flowsnake-table.pl
#
# Print the state tables used for Math:PlanePath::Flowsnake n_to_xy().
use 5.010;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table14 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
my $entry_str = $aref->[$i]//'undef';
if ($i == $#$aref) {
$entry_str .= ");";
} else {
$entry_str .= ",";
}
if ($i % 14 == 0 && $#$aref > 14) {
printf "%-*s", $entry_width+1, $entry_str;
} else {
printf "%*s", $entry_width+1, $entry_str;
}
if ($i % 14 == 13) {
print " # ",$i-13,",",$i-6,"\n";
if ($i != $#$aref) {
print " ".(" " x length($name));
}
} elsif ($i % 7 == 6) {
print " ";
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
my $entry_str = $aref->[$i]//'undef';
if ($i == $#$aref) {
$entry_str .= ");";
} else {
$entry_str .= ",";
}
if ($i % 12 == 0 && $#$aref > 12) {
printf "%-*s", $entry_width+1, $entry_str;
} else {
printf "%*s", $entry_width+1, $entry_str;
}
if ($i % 12 == 11) {
print "\n";
if ($i != $#$aref) {
print " ".(" " x length($name));
}
} elsif ($i % 6 == 5) {
print " ";
}
}
}
my @next_state;
my @digit_to_i;
my @digit_to_j;
my @state_to_di;
my @state_to_dj;
sub make_state {
my %param = @_;
my $state = 0;
$state *= 6; $state += delete $param{'rot'}; # high
$state *= 2; $state += delete $param{'rev'};
$state *= 7; $state += delete $param{'digit'}; # low
if (%param) { die; }
return $state;
}
sub state_string {
my ($state) = @_;
my $digit = $state % 7; $state = int($state/7); # low
my $rev = $state % 2; $state = int($state/2);
my $rot = $state % 6; $state = int($state/6); # high
return "rot=$rot rev=$rev (digit=$digit)";
}
foreach my $rev (0, 1) {
foreach my $rot (0 .. 5) {
foreach my $digit (0 .. 6) {
my $state = make_state (rot => $rot,
rev => $rev,
digit => $digit);
my $new_rev = $rev;
my $new_rot = $rot;
my $plain_digit = ($rev ? 6-$digit : $digit);
my ($i, $j);
if ($rev) {
# 6<---7
# ^
# /
# 0 5<--4
# \ \
# v v
# 1<--2<--3
if ($digit == 0) {
$i = 0;
$j = 0;
$new_rev = 0;
$new_rot -= 1;
} elsif ($digit == 1) {
$i = 1;
$j = -1;
$new_rev = 1;
} elsif ($digit == 2) {
$i = 2;
$j = -1;
$new_rev = 1;
} elsif ($digit == 3) {
$i = 3;
$j = -1;
$new_rot += 2;
$new_rev = 1;
} elsif ($digit == 4) {
$i = 2;
$j = 0;
$new_rot += 3;
$new_rev = 0;
} elsif ($digit == 5) {
$i = 1;
$j = 0;
$new_rot += 1;
$new_rev = 0;
} elsif ($digit == 6) {
$i = 1;
$j = 1;
$new_rev = 1;
}
} else {
# 4-->5-->6
# ^ ^
# \ \
# 3-->2 7
# /
# v
# 0-->1
if ($digit == 0) {
$i = 0;
$j = 0;
$new_rev = 0;
} elsif ($digit == 1) {
$i = 1;
$j = 0;
$new_rev = 1;
$new_rot++;
} elsif ($digit == 2) {
$i = 1;
$j = 1;
$new_rev = 1;
$new_rot += 3;
} elsif ($digit == 3) {
$i = 0;
$j = 1;
$new_rev = 0;
$new_rot += 2;
} elsif ($digit == 4) {
$i = -1;
$j = 2;
$new_rev = 0;
} elsif ($digit == 5) {
$i = 0;
$j = 2;
$new_rev = 0;
} elsif ($digit == 6) {
$i = 1;
$j = 2;
$new_rev = 1;
$new_rot += 5;
}
}
foreach (1 .. $rot) {
($i,$j) = (-$j, $i+$j); # rotate +60
}
$new_rot %= 6;
my $next_state = make_state
(rot => $new_rot,
rev => $new_rev,
digit => 0);
$next_state[$state] = $next_state;
$digit_to_i[$state] = $i;
$digit_to_j[$state] = $j;
}
my $state = make_state (rot => $rot,
rev => $rev,
digit => 0);
my $di = 1;
my $dj = 0;
foreach (1 .. $rot) {
($di,$dj) = (-$dj, $di+$dj); # rotate +60
}
$state_to_di[$state/7] = $di;
$state_to_dj[$state/7] = $dj;
}
}
my @digit_to_next_di;
my @digit_to_next_dj;
my $end_i = 2;
my $end_j = 1;
my $state = 0;
foreach my $rot (0 .. 5) {
foreach my $rev (0, 1) {
foreach my $digit (0 .. 5) {
my $di;
if ($digit < 5) {
$di = $digit_to_i[$state + $digit + 2]
} else {
$di = $end_i;
}
$di -= $digit_to_i[$state + $digit + 1];
$digit_to_next_di[$state + $digit] = $di;
my $dj;
if ($digit < 5) {
$dj = $digit_to_j[$state + $digit + 2];
} else {
$dj = $end_j;
}
$dj -= $digit_to_j[$state + $digit + 1];
$digit_to_next_dj[$state + $digit] = $dj;
if ($di == 0 && $dj == 0) {
die "no delta at state=$state digit=$digit";
}
if ($rev) {
if ($digit == 0) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
} elsif ($digit == 1) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
} elsif ($digit == 2) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
} elsif ($digit == 5) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
}
} else {
if ($digit == 0) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
} elsif ($digit == 1) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
} elsif ($digit == 5) {
($di,$dj) = ($di+$dj, -$di); # rotate -60
}
}
$digit_to_next_di[$state + $digit + 84] = $di;
$digit_to_next_dj[$state + $digit + 84] = $dj;
}
$state += 7;
}
($end_i,$end_j) = (-$end_j, $end_i+$end_j); # rotate +60
}
### @next_state
### @digit_to_dxdy
### next_state length: 4*(4*2*2 + 4*2)
print "# next_state length ", scalar(@next_state), "\n";
print_table14 ("next_state", \@next_state);
print_table14 ("digit_to_i", \@digit_to_i);
print_table14 ("digit_to_j", \@digit_to_j);
print_table12 ("state_to_di", \@state_to_di);
print_table12 ("state_to_dj", \@state_to_dj);
print "\n";
print_table14 ("digit_to_next_di", \@digit_to_next_di);
print "\n";
print_table14 ("digit_to_next_dj", \@digit_to_next_dj);
print "\n";
exit 0;
Math-PlanePath-113/tools/moore-spiral-table.pl 0000644 0001750 0001750 00000006637 11713712763 017116 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
# uncomment this to run the ### lines
#use Smart::Comments;
sub make_state {
my ($rev, $rot) = @_;
$rev %= 2;
$rot %= 4;
return 10*($rot + 4*$rev);
}
sub state_string {
my ($state) = @_;
my $digit = $state % 10; $state = int($state/10);
my $rot = $state % 4; $state = int($state/4);
my $rev = $state % 2; $state = int($state/2);
return "rot=$rot rev=$rev" . ($digit ? " digit=$digit" : "");
}
my @min_digit;
my @max_digit;
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;
my @unrot_digit_to_x = (0,1,1, 0,-1,-2, -2,-2,-3, -3);
my @unrot_digit_to_y = (0,0,1, 1, 1, 1, 0,-1,-1, 0);
my @segment_to_rev = (0,0,0, 1,0,0, 1,1,1, 0);
my @segment_to_dir = (0,1,2, 2,2,3, 3,2,1, 0);
foreach my $rot (0, 1, 2, 3) {
foreach my $rev (0, 1) {
my $state = make_state ($rev, $rot);
foreach my $digit (0 .. 9) {
my $xo = $unrot_digit_to_x[$rev ? 9-$digit : $digit];
my $yo = $unrot_digit_to_y[$rev ? 9-$digit : $digit];
if ($rev) { $xo += 3 }
my $new_rev = $rev ^ $segment_to_rev[$rev ? 8-$digit : $digit];
my $new_rot = $rot + $segment_to_dir[$rev ? 8-$digit : $digit];
if ($new_rev) {
$new_rot += 0;
} else {
$new_rot += 2;
}
if ($rev) {
$new_rot += 2;
} else {
$new_rot += 0;
}
if ($rot & 2) {
$xo = - $xo;
$yo = - $yo;
}
if ($rot & 1) {
($xo,$yo) = (-$yo,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$digit] = $xo;
$digit_to_y[$state+$digit] = $yo;
# $xy_to_digit[$state + 3*$xo + $yo] = $orig_digit;
my $next_state = make_state ($new_rev, $new_rot);
if ($digit == 9) { $next_state = undef; }
$next_state[$state+$digit] = $next_state;
}
}
}
use List::Util 'min','max';
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined && length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print "); # ",$i-9,"\n";
} else {
print ",";
if (($i % 10) == 9) {
print " # ".($i-9);
}
if (($i % 10) == 9) {
print "\n ".(" " x length($name));
} elsif (($i % 3) == 2) {
print " ";
}
}
}
}
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
# print_table ("xy_to_digit", \@xy_to_digit);
# print_table36 ("min_digit", \@min_digit);
# print_table36 ("max_digit", \@max_digit);
print "# state length ",scalar(@next_state)," in each of 4 tables\n";
print "# rot2 state ",make_state(0,2),"\n";
exit 0;
Math-PlanePath-113/tools/cellular-rule-limits.pl 0000644 0001750 0001750 00000040265 12160153756 017460 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::CellularRule;
# uncomment this to run the ### lines
#use Smart::Comments;
my %h;
use Tie::IxHash;
tie %h, 'Tie::IxHash';
foreach my $rule (0 .. 255) {
print "$rule\n";
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
next unless ref $path eq 'Math::PlanePath::CellularRule';
my @x;
my @y;
my @sumxy;
my @diffxy;
my @dx;
my @dy;
my @dsumxy;
my @ddiffxy;
foreach my $n ($path->n_start .. 20000) {
my ($x,$y) = $path->n_to_xy($n)
or last;
push @x, $x;
push @y, $y;
push @sumxy, $x+$y;
push @diffxy, $x-$y;
if (my ($dx,$dy) = $path->n_to_dxdy($n)) {
push @dx, $dx;
push @dy, $dy;
push @dsumxy, $dx+$dy;
push @ddiffxy, $dx-$dy;
}
}
$h{'x_minimum'}->[$rule] = min(@x);
$h{'x_maximum'}->[$rule] = max(@x);
$h{'y_maximum'}->[$rule] = max(@y);
$h{'dx_minimum'}->[$rule] = min(@dx);
$h{'dx_maximum'}->[$rule] = max(@dx);
$h{'dy_minimum'}->[$rule] = min(@dy);
$h{'dy_maximum'}->[$rule] = max(@dy);
$h{'absdx_minimum'}->[$rule] = min(map{abs}@dx);
$h{'absdx_maximum'}->[$rule] = max(map{abs}@dx);
$h{'absdy_minimum'}->[$rule] = min(map{abs}@dy);
$h{'sumxy_minimum'}->[$rule] = min(@sumxy);
$h{'sumxy_maximum'}->[$rule] = max(@sumxy);
$h{'diffxy_minimum'}->[$rule] = min(@diffxy);
$h{'diffxy_maximum'}->[$rule] = max(@diffxy);
$h{'dsumxy_minimum'}->[$rule] = min(@dsumxy);
$h{'dsumxy_maximum'}->[$rule] = max(@dsumxy);
$h{'ddiffxy_minimum'}->[$rule] = min(@ddiffxy);
$h{'ddiffxy_maximum'}->[$rule] = max(@ddiffxy);
}
foreach my $name (keys %h) {
print " my \@${name} = (\n";
my $aref = $h{$name};
while (@$aref && ! defined $aref->[-1]) {
pop @$aref;
}
foreach my $rule (0 .. $#$aref) {
if ($rule % 8 == 0) { print " "; }
my $value = $aref->[$rule];
if (defined $value && ($value < -5 || $value > 5)) { $value = undef; }
if (! defined $value) { $value = 'undef'; }
printf " %5s,", $value;
if ($rule % 8 == 7 || $rule == $#$aref) { print "\n"; }
}
}
exit 0;
__END__
my @dx_minimum = (
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -2, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -2, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 0, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 0, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -2, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -2, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 0, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 0, undef, undef, undef,
undef, undef, undef, undef, undef, undef,
my @dy_maximum = (
undef, 2, undef, 1, undef, 1, undef, 2,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, 2, undef, 2, 1, 2,
undef, 1, undef, 1, 1, 1, 1, 2,
undef, 2, undef, 1, undef, 1, undef, 1,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, 1, undef, 1, undef, 2,
undef, undef, undef, 1, undef, 1, 1, 2,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, 1, 1, 1, 1, 2,
undef, 1, undef, 1, 1, 1, 1, 2,
undef, 2, undef, undef, undef, 1, undef, 1,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, 1, 1, 1, 1, 2,
undef, 1, undef, 1, 1, 1, 1, 2,
undef, 2, undef, 1, undef, 1, undef, 1,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, 1, undef, 1, 1, undef,
undef, 1, undef, 1, 1, 1, 1, undef,
undef, 2, undef, 1, undef, 1, undef, 1,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 1, undef, undef, undef, 1, 1, undef,
undef, 1, undef, 1, 1, 1, undef, undef,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 2, undef, 1, undef, 1, undef, 1,
undef, 1, undef, 1, 1, 1, 1, undef,
undef, 1, undef, 1, undef, 1, undef, undef,
undef, 2, undef, 1, undef, 1, 1, 1,
undef, 2, undef, 1, undef, 1, undef, 1,
undef, 1, undef, 1, 1, 1, undef, undef,
undef, 1, undef, 1, undef, 1,
my @absdy_minimum = (
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, undef, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, undef, undef, 0, undef, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, undef,
undef, 0, undef, 0, 0, 0, 0, undef,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, undef, undef, 0, 0, undef,
undef, 0, undef, 0, 0, 0, undef, undef,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, 0, 0, 0, undef,
undef, 0, undef, 0, undef, 0, undef, undef,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, 0, 0, undef, undef,
undef, 0, undef, 0, undef, 0,
my @sum_maximum = (
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, 1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, 1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, 1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, 1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
0, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef,
my @diff_maximum = (
0, 0, undef, 0, undef, 0, undef, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
0, 0, undef, 0, undef, 0, undef, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, undef, 0,
undef, undef, undef, 0, undef, 0, 0, 0,
0, 0, undef, 0, undef, 0, 0, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
0, 0, undef, undef, undef, 0, undef, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
undef, 0, undef, 0, 0, 0, 0, 0,
0, 0, undef, 0, undef, 0, undef, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, 0, undef, 0, 0, undef,
undef, 0, undef, 0, 0, 0, 0, undef,
0, 0, undef, 0, undef, 0, undef, 0,
0, 0, undef, 0, undef, 0, 0, 0,
undef, 0, undef, undef, undef, 0, 0, undef,
undef, 0, undef, 0, 0, 0, undef, undef,
0, 0, undef, 0, undef, 0, 0, 0,
0, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, 0, 0, 0, undef,
undef, 0, undef, 0, undef, 0, undef, undef,
0, 0, undef, 0, undef, 0, 0, 0,
0, 0, undef, 0, undef, 0, undef, 0,
undef, 0, undef, 0, 0, 0, undef, undef,
undef, 0, undef, 0, undef, 0,
my @dsum_minimum = (
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -1, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, 1, undef, undef, undef,
undef, undef, undef, undef, undef, undef,
my @ddiffxy_minimum = (
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -3, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -3, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, -1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, -1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -3, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, -3, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, -1, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, undef, undef, undef, undef,
undef, undef, undef, undef, -1, undef, undef, undef,
undef, undef, undef, undef, undef, undef,
Math-PlanePath-113/tools/terdragon-midpoint-offset.pl 0000644 0001750 0001750 00000003216 11711717744 020502 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use Math::PlanePath::TerdragonMidpoint;
# uncomment this to run the ### lines
#use Smart::Comments;
my $path = Math::PlanePath::TerdragonMidpoint->new (arms => 1);
my @yx_to_dxdy;
foreach my $n (0 .. 3**10) {
my ($x,$y) = $path->n_to_xy($n);
my $to_n = $n;
if (($n % 3) == 0) {
$to_n = $n + 1;
} elsif (($n % 3) == 2) {
$to_n = $n - 1;
}
my ($to_x,$to_y) = $path->n_to_xy($to_n);
my $dx = $to_x - $x;
my $dy = $to_y - $y;
my $k = 2*(12*($y%12) + ($x%12));
$yx_to_dxdy[$k+0] = $dx;
$yx_to_dxdy[$k+1] = $dy;
}
print_72(\@yx_to_dxdy);
sub print_72 {
my ($aref) = @_;
print "(";
for (my $i = 0; $i < @$aref; ) {
my $v1 = $aref->[$i++] // 'undef';
my $v2 = $aref->[$i++] // 'undef';
my $str = "$v1,$v2";
if ($i != $#$aref) { $str .= ", " }
my $width = (($i % 4) == 2 ? 6 : 6);
printf "%-*s", $width, $str;
if (($i % 12) == 0) { print "\n " }
}
print ");\n";
}
exit 0;
Math-PlanePath-113/tools/corner-replicate-table.pl 0000644 0001750 0001750 00000007052 11660104640 017721 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
# There's no states for CornerReplicate, just two tables of 9 values for
# min/max digits.
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%d", $aref->[$i];
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub print_table9 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 9) == 8) {
print "\n ".(" " x length($name));
} elsif (($i % 3) == 2) {
print " ";
}
}
}
}
my @min_digit;
my @max_digit;
# range 0 [X,_]
# range 1 [X,X]
# range 2 [_,X]
foreach my $xrange (0,1,2) {
foreach my $yrange (0,1,2) {
my $xr = $xrange;
my $yr = $yrange;
my $key = $xr + 3*$yr; # before rot+transpose
my ($min_digit, $max_digit);
# 3--2
# |
# 0--1
if ($xr == 0) {
# 0 or 3
if ($yr == 0) {
# x,y both low, 0 only
$min_digit = 0;
$max_digit = 0;
} elsif ($yr == 1) {
# y either, 0 or 3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 3 only
$min_digit = 3;
$max_digit = 3;
}
} elsif ($xr == 1) {
# x either, any 0,1,2,3
if ($yr == 0) {
# y low, 0 or 1
$min_digit = 0;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 0,1,2,3
$min_digit = 0;
$max_digit = 3;
} elsif ($yr == 2) {
# y high, 2,3 only
$min_digit = 2;
$max_digit = 3;
}
} else {
# x high, 1 or 2
if ($yr == 0) {
# y low, 1 only
$min_digit = 1;
$max_digit = 1;
} elsif ($yr == 1) {
# y either, 1 or 2
$min_digit = 1;
$max_digit = 2;
} elsif ($yr == 2) {
# y high, 2 only
$min_digit = 2;
$max_digit = 2;
}
}
if (defined $min_digit[$key]) {
die "oops min_digit[] already: key=$key value=$min_digit[$key], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
print_table9 ("min_digit", \@min_digit);
print_table9 ("max_digit", \@max_digit);
print "\n";
exit 0;
Math-PlanePath-113/tools/wythoff-array-zeck.pl 0000644 0001750 0001750 00000003746 12113742706 017145 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl wythoff-array-zeck.pl
#
# Print some of the Wythoff array with N values in Zeckendorf base.
#
use 5.010;
use strict;
use List::Util 'max';
use Math::NumSeq::Fibbinary;
use Math::PlanePath::WythoffArray;
my $class = 'Math::PlanePath::WythoffArray';
# $class = 'Math::PlanePath::WythoffDifference';
# $class = 'Math::PlanePath::WythoffPreliminaryTriangle';
my $width = 4;
my $height = 9;
eval "require $class";
my $path = $class->new;
my $fib = Math::NumSeq::Fibbinary->new;
my @z;
my @colwidth;
foreach my $x (0 .. $width) {
foreach my $y (0 .. $height) {
my $n = $path->xy_to_n ($x,$y);
my $z = $n && $fib->ith($n);
my $zb = $z && sprintf '%b', $z;
# $zb = $n && sprintf '%d', $n;
if (! defined $n) { $zb = ''; }
$z[$x][$y] = $zb;
$colwidth[$x] = max($colwidth[$x]||0, length($z[$x][$y]));
}
}
my $ywidth = length($height);
foreach my $y (reverse 0 .. $height) {
printf "%*d |", $ywidth, $y;
foreach my $x (0 .. $width) {
my $value = $z[$x][$y] // '';
printf " %*s", $colwidth[$x], $z[$x][$y];
}
print "\n";
}
printf "%*s +-", $ywidth, '';
foreach my $x (0 .. $width) {
print '-' x ($colwidth[$x]+1);
}
print "\n";
printf "%*s ", $ywidth, '';
foreach my $x (0 .. $width) {
printf " %*s", $colwidth[$x], $x;
}
print "\n";
exit 0;
Math-PlanePath-113/tools/dekking-centres-table.pl 0000644 0001750 0001750 00000013745 12020130531 017533 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*d", $entry_width, $aref->[$i];
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if ($entry_width >= 2 && ($i % 25) == 4) {
print " # ".($i-4);
}
if (($i % 25) == 24
|| $entry_width >= 2 && ($i % 5) == 4) {
print "\n ".(" " x length($name));
} elsif (($i % 5) == 4) {
print " ";
}
}
}
}
sub make_state {
my ($rev, $rot) = @_;
$rev %= 2;
$rot %= 4;
return 25*($rot + 4*$rev);
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @yx_to_digit;
foreach my $rev (0, 1) {
foreach my $rot (0, 1, 2, 3) {
foreach my $orig_digit (0 .. 24) {
my $digit = $orig_digit;
if ($rev) {
$digit = 24-$digit;
}
my $xo;
my $yo;
my $new_rot = $rot;
my $new_rev = $rev;
if ($digit == 0) {
$xo = 0;
$yo = 0;
} elsif ($digit == 1) {
$xo = 1;
$yo = 0;
} elsif ($digit == 2) {
$xo = 2;
$yo = 0;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 3) {
$xo = 1;
$yo = 1;
$new_rev ^= 1;
} elsif ($digit == 4) {
$xo = 0;
$yo = 1;
$new_rot = $rot + 1;
} elsif ($digit == 5) {
$xo = 1;
$yo = 2;
} elsif ($digit == 6) {
$xo = 2;
$yo = 2;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 7) {
$xo = 1;
$yo = 3;
$new_rev ^= 1;
} elsif ($digit == 8) {
$xo = 0;
$yo = 2;
$new_rot = $rot + 2;
} elsif ($digit == 9) {
$xo = 0;
$yo = 3;
$new_rot = $rot - 1;
$new_rev ^= 1;
} elsif ($digit == 10) {
$xo = 0;
$yo = 4;
} elsif ($digit == 11) {
$xo = 1;
$yo = 4;
} elsif ($digit == 12) {
$xo = 2;
$yo = 3;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 13) {
$xo = 2;
$yo = 4;
$new_rot = $rot + 1;
} elsif ($digit == 14) {
$xo = 3;
$yo = 4;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 15) {
$xo = 4;
$yo = 4;
$new_rot = $rot - 1;
} elsif ($digit == 16) {
$xo = 4;
$yo = 3;
$new_rot = $rot - 1;
} elsif ($digit == 17) {
$xo = 3;
$yo = 3;
$new_rev ^= 1;
} elsif ($digit == 18) {
$xo = 3;
$yo = 2;
$new_rot = $rot - 1;
} elsif ($digit == 19) {
$xo = 2;
$yo = 1;
$new_rot = $rot + 1;
$new_rev ^= 1;
} elsif ($digit == 20) {
$xo = 3;
$yo = 0;
$new_rot = $rot + 2;
$new_rev ^= 1;
} elsif ($digit == 21) {
$xo = 3;
$yo = 1;
$new_rot = $rot + 1;
} elsif ($digit == 22) {
$xo = 4;
$yo = 2;
} elsif ($digit == 23) {
$xo = 4;
$yo = 1;
$new_rot = $rot + 1;
$new_rev ^= 1;
} elsif ($digit == 24) {
$xo = 4;
$yo = 0;
$new_rot = $rot + 1;
$new_rev ^= 1;
} else {
die;
}
### base: "$xo, $yo"
if ($rot & 2) {
$xo = 4 - $xo;
$yo = 4 - $yo;
}
if ($rot & 1) {
($xo,$yo) = (4-$yo,$xo);
}
### rot to: "$xo, $yo"
my $state = make_state ($rev, $rot);
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$yx_to_digit[$state + $yo*5+$xo] = $orig_digit;
my $next_state = make_state ($new_rev, $new_rot);
$next_state[$state+$orig_digit] = $next_state;
}
}
}
print "# state length ",scalar(@next_state)," in each of 4 tables\n";
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("yx_to_digit", \@yx_to_digit);
### @next_state
### @digit_to_x
### @digit_to_y
### @yx_to_digit
### next_state length: scalar(@next_state)
{
my @pending_state = (0);
my $count = 0;
my @seen_state;
my $depth = 1;
$seen_state[0] = $depth;
while (@pending_state) {
my $state = pop @pending_state;
$count++;
### consider state: $state
foreach my $digit (0 .. 24) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
for (my $state = 0; $state < @next_state; $state += 25) {
print "# used state $state depth $seen_state[$state]\n";
}
print "used state count $count\n";
}
print "\n";
exit 0;
Math-PlanePath-113/tools/cinco-curve-table.pl 0000644 0001750 0001750 00000020232 11665051545 016705 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'min','max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub min_maybe {
return min(grep {defined} @_);
}
sub max_maybe {
return max(grep {defined} @_);
}
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'undef')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if ($entry_width >= 2 && ($i % 25) == 4) {
print " # ".($i-4);
}
if (($i % 25) == 24
|| $entry_width >= 2 && ($i % 5) == 4) {
print "\n ".(" " x length($name));
} elsif (($i % 5) == 4) {
print " ";
}
}
}
}
sub make_state {
my ($transpose, $rot) = @_;
$transpose %= 2;
$rot %= 4;
unless ($rot == 0 || $rot == 2) {
die "bad rotation $rot";
}
return 25*($rot/2 + 2*$transpose);
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @yx_to_digit;
my @min_digit;
my @max_digit;
foreach my $transpose (0, 1) {
foreach my $rot (0, 2) {
my $state = make_state ($transpose, $rot);
### $state
foreach my $orig_digit (0 .. 24) {
my $digit = $orig_digit;
# if ($rev) {
# $digit = 24-$digit;
# }
my $xo;
my $yo;
my $new_rot = $rot;
my $new_transpose = $transpose;
my $inc_rot = 0;
if ($digit == 0) {
$xo = 0;
$yo = 0;
} elsif ($digit == 1) {
$xo = 1;
$yo = 0;
} elsif ($digit == 2) {
$xo = 2;
$yo = 0;
$new_transpose ^= 1;
} elsif ($digit == 3) {
$xo = 2;
$yo = 1;
$new_transpose ^= 1;
} elsif ($digit == 4) {
$xo = 2;
$yo = 2;
$new_transpose ^= 1;
} elsif ($digit == 5) {
$xo = 1;
$yo = 2;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 6) {
$xo = 1;
$yo = 1;
$inc_rot = 2;
} elsif ($digit == 7) {
$xo = 0;
$yo = 1;
$inc_rot = 2;
} elsif ($digit == 8) {
$xo = 0;
$yo = 2;
$new_transpose ^= 1;
} elsif ($digit == 9) {
$xo = 0;
$yo = 3;
$new_transpose ^= 1;
} elsif ($digit == 10) {
$xo = 0;
$yo = 4;
} elsif ($digit == 11) {
$xo = 1;
$yo = 4;
} elsif ($digit == 12) {
$xo = 1;
$yo = 3;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 13) {
$xo = 2;
$yo = 3;
$new_transpose ^= 1;
} elsif ($digit == 14) {
$xo = 2;
$yo = 4;
} elsif ($digit == 15) {
$xo = 3;
$yo = 4;
} elsif ($digit == 16) {
$xo = 4;
$yo = 4;
} elsif ($digit == 17) {
$xo = 4;
$yo = 3;
$inc_rot = 2;
} elsif ($digit == 18) {
$xo = 3;
$yo = 3;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 19) {
$xo = 3;
$yo = 2;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 20) {
$xo = 4;
$yo = 2;
} elsif ($digit == 21) {
$xo = 4;
$yo = 1;
$inc_rot = 2;
} elsif ($digit == 22) {
$xo = 3;
$yo = 1;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 23) {
$xo = 3;
$yo = 0;
$inc_rot = 2;
$new_transpose ^= 1;
} elsif ($digit == 24) {
$xo = 4;
$yo = 0;
} else {
die;
}
### base: "$xo, $yo"
if ($transpose) {
($xo,$yo) = ($yo,$xo);
$inc_rot = - $inc_rot;
}
$new_rot = $rot + $inc_rot;
if ($rot & 2) {
$xo = 4 - $xo;
$yo = 4 - $yo;
}
if ($rot & 1) {
($xo,$yo) = (4-$yo,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$yx_to_digit[$state + $yo*5+$xo] = $orig_digit;
my $next_state = make_state ($new_transpose, $new_rot);
$next_state[$state+$orig_digit] = $next_state;
}
# N = (- 1/2 d^2 + 9/2 d)
# = (- 1/2*$d**2 + 9/2*$d)
# = ((9 - d)d/2
# (9-d)*d/2
# d=0 (9-0)*0/2 = 0
# d=1 (9-1)*1/2 - 1 = 8/2-1 = 3
# d=2 (9-2)*2/2 - 2 = 7-1 = 6
# d=4 (9-4)*4/2 = 5*4/2 = 10
#
foreach my $x1pos (0 .. 4) {
foreach my $x2pos ($x1pos .. 4) {
my $xkey = (9-$x1pos)*$x1pos/2 + $x2pos;
### $xkey
### assert: $xkey >= 0
### assert: $xkey < 15
foreach my $y1pos (0 .. 4) {
foreach my $y2pos ($y1pos .. 4) {
my $ykey = (9-$y1pos)*$y1pos/2 + $y2pos;
### $ykey
### assert: $ykey >= 0
### assert: $ykey < 15
my $min_digit = undef;
my $max_digit = undef;
foreach my $digit (0 .. 24) {
my $x = $digit_to_x[$digit];
my $y = $digit_to_y[$digit];
if ($rot & 2) {
$x = 4 - $x;
$y = 4 - $y;
}
if ($transpose) {
($x,$y) = ($y,$x);
}
next unless $x >= $x1pos;
next unless $x <= $x2pos;
next unless $y >= $y1pos;
next unless $y <= $y2pos;
$min_digit = min_maybe($digit,$min_digit);
$max_digit = max_maybe($digit,$max_digit);
}
my $key = $state*9 + $xkey*15 + $ykey;
### $key
if (defined $min_digit[$key]) {
die "oops min_digit[] already: state=$state key=$key y1p=$y1pos y2p=$y2pos value=$min_digit[$key], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
}
}
}
}
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("yx_to_digit", \@yx_to_digit);
print_table ("min_digit", \@min_digit);
print_table ("max_digit", \@max_digit);
print "# state length ",scalar(@next_state)," in each of 4 tables\n\n";
### @next_state
### @digit_to_x
### @digit_to_y
### @yx_to_digit
### next_state length: scalar(@next_state)
{
my @pending_state = (0);
my $count = 0;
my @seen_state;
my $depth = 1;
$seen_state[0] = $depth;
while (@pending_state) {
my $state = pop @pending_state;
$count++;
### consider state: $state
foreach my $digit (0 .. 24) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
for (my $state = 0; $state < @next_state; $state += 25) {
print "# used state $state depth ",$seen_state[$state]//'undef',"\n";
}
print "used state count $count\n";
}
print "\n";
exit 0;
Math-PlanePath-113/tools/gallery.pl 0000644 0001750 0001750 00000143307 12254143252 015043 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl gallery.pl
#
# Create the .png files in $target_dir = "$ENV{HOME}/tux/web/math-planepath"
# as appearing at http://user42.tuxfamily.org/math-planepath/gallery.html
#
use 5.004;
use strict;
use warnings;
use File::Compare ();
use File::Copy;
use File::Temp;
use Image::Base::GD;
use POSIX 'floor';
# uncomment this to run the ### lines
# use Smart::Comments;
my $target_dir = "$ENV{HOME}/tux/web/math-planepath";
my $tempfh = File::Temp->new (SUFFIX => '.png');
my $tempfile = $tempfh->filename;
my $big_bytes = 0;
my %seen_filename;
foreach my $elem
(
['htree-big.png',
'math-image --path=HTree --values=LinesTree --scale=6 --size=196 --offset=2,2 --figure=point'],
['htree-small.png',
'math-image --path=HTree --values=LinesTree --scale=4 --size=32 --offset=2,2'],
['pythagorean-tree-uard-rows-pq.png',
'math-image --path=PythagoreanTree,tree_type=UArD,digit_order=LtoH,coordinates=PQ --lines --scale=14 --size=200 --figure=point'],
['pythagorean-tree-uard-rows.png',
'math-image --path=PythagoreanTree,tree_type=UArD,digit_order=LtoH --lines --scale=1 --size=200 --figure=point'],
['pythagorean-tree-umt-big.png',
'math-image --path=PythagoreanTree,tree_type=UMT --values=LinesTree --scale=4 --size=200'],
['pythagorean-tree-fb-big.png',
'math-image --path=PythagoreanTree,tree_type=FB --values=LinesTree --scale=4 --size=200'],
['pythagorean-tree-big.png',
'math-image --path=PythagoreanTree --values=LinesTree --scale=4 --size=200'],
['pythagorean-points-sm-big.png',
'math-image --path=PythagoreanTree,coordinates=SM --all --scale=1 --size=150'],
['pythagorean-points-sc-big.png',
'math-image --path=PythagoreanTree,coordinates=SC --all --scale=1 --size=150'],
['pythagorean-points-mc-big.png',
'math-image --path=PythagoreanTree,coordinates=MC --all --scale=1 --size=150'],
['pythagorean-points-bc-big.png',
'math-image --path=PythagoreanTree,coordinates=BC --all --scale=1 --size=200'],
['pythagorean-points-ac-big.png',
'math-image --path=PythagoreanTree,coordinates=AC --all --scale=1 --size=200'],
['pythagorean-small.png',
'math-image --path=PythagoreanTree --values=LinesTree --scale=1 --size=32'],
['pythagorean-points-big.png',
'math-image --path=PythagoreanTree --all --scale=1 --size=200'],
['chan-tree-rows-ltoh.png', \&special_chan_rows,
title => 'ChanTree,digit_order=LtoH rows' ],
['cfrac-digits-growth.png',
"math-image --path=CfracDigits --expression='i<=3**7?i:0' --scale=1 --size=100x200"],
['cfrac-digits-small.png',
'math-image --path=CfracDigits --lines --scale=4 --size=32 --offset=-4,-8'],
['cfrac-digits-big.png',
'math-image --path=CfracDigits --lines --scale=10 --size=200'],
['cfrac-digits-radix3.png',
'math-image --path=CfracDigits,radix=3 --lines --scale=10 --size=200'],
['cfrac-digits-radix4.png',
'math-image --path=CfracDigits,radix=4 --lines --scale=10 --size=200'],
['gcd-rationals-rows-big.png',
"math-image --path=GcdRationals --expression='i<=68*67/2?i:0' --scale=2 --size=160x200"],
['gcd-rationals-diagonals-big.png',
"math-image --path=GcdRationals,pairs_order=diagonals_down --expression='i<=47**2?i:0' --scale=2 --size=160x200"],
['gcd-rationals-small.png',
'math-image --path=GcdRationals --lines --scale=6 --size=32 --offset=-4,-4'],
['gcd-rationals-big.png',
'math-image --path=GcdRationals --lines --scale=15 --size=200'],
['gcd-rationals-reverse-big.png',
'math-image --path=GcdRationals,pairs_order=rows_reverse --lines --scale=15 --size=200'],
['chan-tree-lines.png',
'math-image --path=ChanTree --values=LinesTree --scale=12 --size=200'],
['chan-tree-small.png',
'math-image --path=ChanTree --all --scale=2 --size=32'],
['chan-tree-big.png',
'math-image --path=ChanTree --all --scale=3 --size=200'],
['chan-tree-k4.png',
'math-image --path=ChanTree,k=4 --all --scale=3 --size=200'],
['chan-tree-k5.png',
'math-image --path=ChanTree,k=5 --all --scale=3 --size=200'],
['toothpick-spiral-small.png',
'math-image --path=ToothpickSpiral --values=Lines --scale=5 --size=32 --figure=point'],
['toothpick-spiral-big.png',
'math-image --path=ToothpickSpiral --values=Lines --scale=9 --size=200x200'],
['toothpick-upist-small.png',
'math-image --path=ToothpickUpist --values=LinesTree --scale=4 --size=32 --figure=toothpick --offset=0,5'],
['toothpick-upist-big.png',
'math-image --path=ToothpickUpist --values=LinesTree --scale=5 --size=300x150 --figure=toothpick'],
['lcorner-tree-1.png',
'math-image --path=LCornerTree,parts=1 --values=LinesTree --scale=7 --size=99'],
['lcorner-tree-big.png',
'math-image --path=LCornerTree --values=LinesTree --scale=7 --size=199'],
['lcorner-tree-octant-up.png',
'math-image --path=LCornerTree,parts=octant_up --values=LinesTree --scale=7 --size=99 --figure=point'],
['lcorner-tree-octant-up+1.png',
'math-image --path=LCornerTree,parts=octant_up+1 --values=LinesTree --scale=7 --size=99 --figure=point'],
['lcorner-tree-wedge.png',
'math-image --path=LCornerTree,parts=wedge --values=LinesTree --scale=6 --size=200x95 --figure=point'],
['lcorner-tree-wedge+1.png',
'math-image --path=LCornerTree,parts=wedge+1 --values=LinesTree --scale=6 --size=200x95 --figure=point'],
['lcorner-tree-octant.png',
'math-image --path=LCornerTree,parts=octant --values=LinesTree --scale=7 --size=99 --figure=point'],
['lcorner-tree-octant+1.png',
'math-image --path=LCornerTree,parts=octant+1 --values=LinesTree --scale=7 --size=99 --figure=point'],
['lcorner-tree-diagonal.png',
'math-image --path=LCornerTree,parts=diagonal --values=LinesTree --scale=7 --size=99 --figure=point'],
['lcorner-tree-diagonal-1.png',
'math-image --path=LCornerTree,parts=diagonal-1 --values=LinesTree --scale=7 --size=99'],
['lcorner-tree-small.png',
'math-image --path=LCornerTree --values=LinesTree --scale=4 --size=32'],
['toothpick-tree-3.png',
'math-image --path=ToothpickTree,parts=3 --values=LinesTree --scale=6 --size=200 --figure=point'],
['toothpick-tree-octant.png',
'math-image --path=ToothpickTree,parts=octant --values=LinesTree --scale=6 --size=200 --figure=point'],
['toothpick-tree-wedge.png',
'math-image --path=ToothpickTree,parts=wedge --values=LinesTree --scale=6 --size=200x104 --figure=toothpick --offset=0,5'],
['toothpick-tree-small.png',
'math-image --path=ToothpickTree --values=LinesTree --scale=4 --size=32'],
['toothpick-tree-big.png',
'math-image --path=ToothpickTree --values=LinesTree --scale=6 --size=200'],
['toothpick-replicate-small.png',
'math-image --path=ToothpickReplicate --lines --scale=4 --size=32 --figure=toothpick'],
['toothpick-replicate-big.png',
'math-image --path=ToothpickReplicate --all --scale=6 --size=200 --figure=toothpick'],
['ulam-warburton-1.png',
"math-image --path=UlamWarburton,parts=1 --values=LinesTree --figure=diamond --scale=8 --size=150"],
['ulam-warburton-2.png',
"math-image --path=UlamWarburton,parts=2 --values=Lines --figure=point --scale=6 --size=360x130"],
['ulam-warburton-tree-big.png',
"math-image --path=UlamWarburton --values=LinesTree --scale=7 --figure=point --size=150"],
['ulam-warburton-small.png',
"math-image --path=UlamWarburton --expression='i<50?i:0' --scale=2 --size=32"],
['ulam-warburton-big.png',
"math-image --path=UlamWarburton --expression='i<233?i:0' --scale=4 --size=150"],
['ulam-warburton-quarter-small.png',
"math-image --path=UlamWarburtonQuarter --expression='i<50?i:0' --scale=2 --size=32"],
['ulam-warburton-quarter-big.png',
"math-image --path=UlamWarburtonQuarter --expression='i<233?i:0' --scale=4 --size=150"],
['one-of-eight-wedge.png',
'math-image --path=OneOfEight,parts=wedge --all --scale=3 --size=200x99'],
['one-of-eight-1-nonleaf.png',
'math-image --path=OneOfEight,parts=1 --values=PlanePathCoord,planepath=\"OneOfEight,parts=1\",coordinate_type=IsNonLeaf --scale=3 --size=99'],
['one-of-eight-small.png',
'math-image --path=OneOfEight --values=LinesTree --scale=4 --size=32'],
['one-of-eight-big.png',
'math-image --path=OneOfEight --values=LinesTree --scale=6 --size=200'],
['one-of-eight-1.png',
'math-image --path=OneOfEight,parts=1 --all --scale=3 --size=99'],
['one-of-eight-octant.png',
'math-image --path=OneOfEight,parts=octant --all --scale=3 --size=99'],
['one-of-eight-3mid.png',
'math-image --path=OneOfEight,parts=3mid --all --scale=3 --size=99'],
['one-of-eight-3side.png',
'math-image --path=OneOfEight,parts=3side --all --scale=3 --size=99'],
['flowsnake-3arm-big.png',
'math-image --path=Flowsnake,arms=3 --lines --scale=6 --size=200 --figure=point'],
['flowsnake-small.png',
'math-image --path=Flowsnake --lines --scale=4 --size=32 --offset=-5,-13'],
['flowsnake-big.png',
'math-image --path=Flowsnake --lines --scale=8 --size=200 --offset=-20,-90'],
['flowsnake-centres-small.png',
'math-image --path=FlowsnakeCentres --lines --scale=4 --size=32 --offset=-5,-13'],
['flowsnake-centres-big.png',
'math-image --path=FlowsnakeCentres --lines --scale=8 --size=200 --offset=-20,-90'],
['rationals-tree-rows-sb.png', \&special_sb_rows,
title => 'RationalsTree,tree_type=SB rows' ],
['rationals-tree-lines-ayt.png',
'math-image --path=RationalsTree,tree_type=AYT --values=LinesTree --scale=20 --size=200'],
['rationals-tree-lines-hcs.png',
'math-image --path=RationalsTree,tree_type=HCS --values=LinesTree --scale=20 --size=200'],
['rationals-tree-lines-l.png',
'math-image --path=RationalsTree,tree_type=L --values=LinesTree --scale=20 --size=200'],
['rationals-tree-small.png',
'math-image --path=RationalsTree --values=LinesTree --scale=8 --size=32 --offset=-8,-8'],
['rationals-tree-big.png',
'math-image --path=RationalsTree --all --scale=3 --size=200'],
['rationals-tree-lines-sb.png',
'math-image --path=RationalsTree,tree_type=SB --values=LinesTree --scale=20 --size=200'],
['rationals-tree-lines-cw.png',
'math-image --path=RationalsTree,tree_type=CW --values=LinesTree --scale=20 --size=200'],
['rationals-tree-lines-bird.png',
'math-image --path=RationalsTree,tree_type=Bird --values=LinesTree --scale=20 --size=200'],
['rationals-tree-lines-drib.png',
'math-image --path=RationalsTree,tree_type=Drib --values=LinesTree --scale=20 --size=200'],
['triangle-spiral-skewed-small.png',
'math-image --path=TriangleSpiralSkewed --lines --scale=3 --size=32'],
['triangle-spiral-skewed-big.png',
'math-image --path=TriangleSpiralSkewed --lines --scale=13 --size=150'],
['triangle-spiral-skewed-right-big.png',
'math-image --path=TriangleSpiralSkewed,skew=right --lines --scale=13 --size=150'],
['triangle-spiral-skewed-up-big.png',
'math-image --path=TriangleSpiralSkewed,skew=up --lines --scale=13 --size=150'],
['triangle-spiral-skewed-down-big.png',
'math-image --path=TriangleSpiralSkewed,skew=down --lines --scale=13 --size=150'],
['triangle-spiral-small.png',
'math-image --path=TriangleSpiral --lines --scale=3 --size=32'],
['triangle-spiral-big.png',
'math-image --path=TriangleSpiral --lines --scale=13 --size=300x150'],
['koch-curve-small.png',
'math-image --path=KochCurve --lines --scale=2 --size=32 --offset=0,8'],
['koch-curve-big.png',
'math-image --path=KochCurve --lines --scale=5 --size=250x100 --offset=0,5'],
['lcorner-replicate-small.png',
'math-image --path=LCornerReplicate --lines --scale=4 --size=32'],
['lcorner-replicate-big.png',
'math-image --path=LCornerReplicate --lines --scale=7 --size=200'],
['imaginaryhalf-small.png',
'math-image --path=ImaginaryHalf --lines --scale=7 --size=32'],
['imaginaryhalf-big.png',
'math-image --path=ImaginaryHalf --lines --scale=18 --size=200'],
['imaginaryhalf-radix5-big.png',
'math-image --path=ImaginaryHalf,radix=5 --lines --scale=18 --size=200'],
['imaginaryhalf-xxy-big.png',
'math-image --path=ImaginaryHalf,digit_order=XXY --lines --scale=10 --size=75'],
['imaginaryhalf-yxx-big.png',
'math-image --path=ImaginaryHalf,digit_order=YXX --lines --scale=10 --size=75'],
['imaginaryhalf-xnyx-big.png',
'math-image --path=ImaginaryHalf,digit_order=XnYX --lines --scale=10 --size=75'],
['imaginaryhalf-xnxy-big.png',
'math-image --path=ImaginaryHalf,digit_order=XnXY --lines --scale=10 --size=75'],
['imaginaryhalf-yxnx-big.png',
'math-image --path=ImaginaryHalf,digit_order=YXnX --lines --scale=10 --size=75'],
['imaginarybase-small.png',
'math-image --path=ImaginaryBase --lines --scale=7 --size=32'],
['imaginarybase-big.png',
'math-image --path=ImaginaryBase --lines --scale=18 --size=200'],
['imaginarybase-radix5-big.png',
'math-image --path=ImaginaryBase,radix=5 --lines --scale=18 --size=200'],
['h-indexing-small.png',
'math-image --path=HIndexing --scale=3 --size=32 --lines --figure=point'],
['h-indexing-big.png',
'math-image --path=HIndexing --lines --scale=5 --size=200 --figure=point'],
['sierpinski-curve-small.png',
'math-image --path=SierpinskiCurve,arms=2 --scale=3 --size=32 --lines --figure=point'],
['sierpinski-curve-big.png',
'math-image --path=SierpinskiCurve --lines --scale=3 --size=200 --figure=point'],
['sierpinski-curve-8arm-big.png',
'math-image --path=SierpinskiCurve,arms=8 --lines --scale=3 --size=200 --figure=point'],
['alternate-paper-midpoint-small.png',
'math-image --path=AlternatePaperMidpoint --lines --scale=3 --size=32'],
['alternate-paper-midpoint-big.png',
'math-image --path=AlternatePaperMidpoint --lines --figure=point --scale=4 --size=200'],
['alternate-paper-midpoint-8arm-big.png',
'math-image --path=AlternatePaperMidpoint,arms=8 --lines --figure=point --scale=4 --size=200'],
['sierpinski-curve-stair-small.png',
'math-image --path=SierpinskiCurveStair,arms=2 --scale=3 --size=32 --lines --figure=point'],
['sierpinski-curve-stair-big.png',
'math-image --path=SierpinskiCurveStair --lines --scale=5 --size=200 --figure=point'],
['sierpinski-curve-stair-8arm-big.png',
'math-image --path=SierpinskiCurveStair,arms=8 --lines --scale=5 --size=200 --figure=point'],
['alternate-paper-small.png',
'math-image --path=AlternatePaper --lines --scale=4 --size=32'],
['alternate-paper-big.png',
'math-image --path=AlternatePaper --lines --figure=point --scale=8 --size=200'],
['alternate-paper-rounded-big.png',
'math-image --path=AlternatePaper --values=Lines,lines_type=rounded,midpoint_offset=0.4 --figure=point --scale=16 --size=200'],
['pyramid-rows-small.png',
'math-image --path=PyramidRows --lines --scale=5 --size=32'],
['pyramid-rows-big.png',
'math-image --path=PyramidRows --lines --scale=15 --size=300x150'],
['pyramid-rows-right-big.png',
'math-image --path=PyramidRows,step=4,align=right --lines --scale=15 --size=300x150'],
['pyramid-rows-left-big.png',
'math-image --path=PyramidRows,step=1,align=left --lines --scale=15 --size=160x150 --offset=65,0'],
['sierpinski-triangle-small.png',
'math-image --path=SierpinskiTriangle --all --scale=2 --size=32'],
['sierpinski-triangle-big.png',
'math-image --path=SierpinskiTriangle --all --scale=3 --size=400x200'],
['sierpinski-triangle-right-big.png',
'math-image --path=SierpinskiTriangle,align=right --all --scale=3 --size=200x200'],
['sierpinski-triangle-left-big.png',
'math-image --path=SierpinskiTriangle,align=left --all --scale=3 --size=200x200 --offset=98,0'],
['sierpinski-triangle-diagonal-big.png',
'math-image --path=SierpinskiTriangle,align=diagonal --values=LinesTree --scale=4 --size=200x200'],
['sierpinski-arrowhead-centres-small.png',
'math-image --path=SierpinskiArrowheadCentres --lines --scale=2 --size=32'],
['sierpinski-arrowhead-centres-big.png',
'math-image --path=SierpinskiArrowheadCentres --lines --scale=3 --size=400x200'],
['sierpinski-arrowhead-centres-right-big.png',
'math-image --path=SierpinskiArrowheadCentres,align=right --lines --scale=4 --size=200x200'],
['sierpinski-arrowhead-centres-left-big.png',
'math-image --path=SierpinskiArrowheadCentres,align=left --lines --scale=4 --size=200x200 --offset=98,0'],
['sierpinski-arrowhead-centres-diagonal-big.png',
'math-image --path=SierpinskiArrowheadCentres,align=diagonal --lines --scale=5 --size=200x200 --figure=point'],
['sierpinski-arrowhead-small.png',
'math-image --path=SierpinskiArrowhead --lines --scale=2 --size=32'],
['sierpinski-arrowhead-big.png',
'math-image --path=SierpinskiArrowhead --lines --scale=3 --size=400x200'],
['sierpinski-arrowhead-right-big.png',
'math-image --path=SierpinskiArrowhead,align=right --lines --scale=4 --size=200x200'],
['sierpinski-arrowhead-left-big.png',
'math-image --path=SierpinskiArrowhead,align=left --lines --scale=4 --size=200x200 --offset=98,0'],
['sierpinski-arrowhead-diagonal-big.png',
'math-image --path=SierpinskiArrowhead,align=diagonal --lines --scale=5 --size=200x200 --figure=point'],
['wunderlich-meander-small.png',
'math-image --path=WunderlichMeander --lines --scale=4 --size=32 --figure=point'],
['wunderlich-meander-big.png',
'math-image --path=WunderlichMeander --lines --scale=7 --size=192 --figure=point'],
['hilbert-small.png',
'math-image --path=HilbertCurve --lines --scale=3 --size=32 --figure=point'],
['hilbert-big.png',
'math-image --path=HilbertCurve --lines --scale=7 --size=225 --figure=point'],
['hilbert-spiral-small.png',
'math-image --path=HilbertSpiral --lines --scale=3 --size=32 --figure=point'],
['hilbert-spiral-big.png',
'math-image --path=HilbertSpiral --lines --scale=7 --size=230 --figure=point'],
['cinco-small.png',
'math-image --path=CincoCurve --lines --scale=6 --size=32 --figure=point'],
['cinco-big.png',
'math-image --path=CincoCurve --lines --scale=7 --size=176 --figure=point'],
['dekking-curve-small.png',
'math-image --path=DekkingCurve --lines --scale=5 --size=32 --figure=point'],
['dekking-curve-big.png',
'math-image --path=DekkingCurve --lines --scale=7 --size=183 --figure=point'],
['dekking-centres-small.png',
'math-image --path=DekkingCentres --lines --scale=6 --size=32 --figure=point'],
['dekking-centres-big.png',
'math-image --path=DekkingCentres --lines --scale=7 --size=176 --figure=point'],
# ['hilbert-midpoint-small.png',
# 'math-image --path=HilbertMidpoint --lines --scale=2 --size=32'],
# ['hilbert-midpoint-big.png',
# 'math-image --path=HilbertMidpoint --lines --scale=3 --size=190'],
['power-array-small.png',
'math-image --path=PowerArray --lines --scale=8 --size=32'],
['power-array-big.png',
'math-image --path=PowerArray --lines --scale=16 --size=200'],
['power-array-radix5-big.png',
'math-image --path=PowerArray,radix=5 --lines --scale=16 --size=200'],
['wythoff-array-small.png',
'math-image --path=WythoffArray --lines --scale=8 --size=32'],
['wythoff-array-big.png',
'math-image --path=WythoffArray --lines --scale=16 --size=200'],
['complexminus-small.png',
"math-image --path=ComplexMinus --expression='i<32?i:0' --scale=2 --size=32"],
['complexminus-big.png',
"math-image --path=ComplexMinus --expression='i<1024?i:0' --scale=3 --size=200"],
['complexminus-r2-small.png',
"math-image --path=ComplexMinus,realpart=2 --expression='i<125?i:0' --scale=2 --size=32"],
['complexminus-r2-big.png',
"math-image --path=ComplexMinus,realpart=2 --expression='i<3125?i:0' --scale=1 --size=200"],
['pyramid-sides-small.png',
'math-image --path=PyramidSides --lines --scale=5 --size=32'],
['pyramid-sides-big.png',
'math-image --path=PyramidSides --lines --scale=15 --size=300x150'],
['triangular-hypot-small.png',
'math-image --path=TriangularHypot --lines --scale=4 --size=32'],
['triangular-hypot-big.png',
'math-image --path=TriangularHypot --lines --scale=15 --size=200x150'],
['triangular-hypot-odd-big.png',
'math-image --path=TriangularHypot,points=odd --lines --scale=15 --size=200x150'],
['triangular-hypot-all-big.png',
'math-image --path=TriangularHypot,points=all --lines --scale=15 --size=200x150'],
['triangular-hypot-hex-big.png',
'math-image --path=TriangularHypot,points=hex --lines --scale=15 --size=200x150'],
['triangular-hypot-hex-rotated-big.png',
'math-image --path=TriangularHypot,points=hex_rotated --lines --scale=15 --size=200x150'],
['triangular-hypot-hex-centred-big.png',
'math-image --path=TriangularHypot,points=hex_centred --lines --scale=15 --size=200x150'],
['greek-key-small.png',
'math-image --path=GreekKeySpiral --lines --scale=4 --size=32'],
['greek-key-big.png',
'math-image --path=GreekKeySpiral --lines --scale=8 --size=200'],
['greek-key-turns1-big.png',
'math-image --path=GreekKeySpiral,turns=1 --lines --scale=8 --figure=point --size=200'],
['greek-key-turns5-big.png',
'math-image --path=GreekKeySpiral,turns=5 --lines --scale=8 --figure=point --size=200'],
['c-curve-small.png',
'math-image --path=CCurve --lines --scale=3 --size=32 --offset=8,0'],
['c-curve-big.png',
'math-image --path=CCurve --lines --figure=point --scale=3 --size=250x250 --offset=20,-70'],
['diagonals-octant-small.png',
'math-image --path=DiagonalsOctant --lines --scale=6 --size=32'],
['diagonals-octant-big.png',
'math-image --path=DiagonalsOctant --lines --scale=15 --size=195'],
['diagonals-alternating-small.png',
'math-image --path=DiagonalsAlternating --lines --scale=6 --size=32'],
['diagonals-alternating-big.png',
'math-image --path=DiagonalsAlternating --lines --scale=15 --size=195'],
['diagonals-small.png',
'math-image --path=Diagonals --lines --scale=6 --size=32'],
['diagonals-big.png',
'math-image --path=Diagonals --lines --scale=15 --size=195'],
['terdragon-rounded-small.png',
'math-image --path=TerdragonRounded --lines --scale=2 --size=32 --offset=-5,-10'],
['terdragon-rounded-big.png',
'math-image --path=TerdragonRounded --lines --figure=point --scale=3 --size=200 --offset=65,-20'],
['terdragon-rounded-6arm-big.png',
'math-image --path=TerdragonRounded,arms=6 --lines --figure=point --scale=5 --size=200'],
['terdragon-small.png',
'math-image --path=TerdragonCurve --lines --scale=5 --size=32 --offset=-3,-7'],
['terdragon-big.png',
'math-image --path=TerdragonCurve --lines --figure=point --scale=4 --size=200 --offset=75,50'],
# ['terdragon-6arm-big.png',
# 'math-image --path=TerdragonCurve,arms=6 --lines --figure=point --scale=4 --size=200'],
# ['terdragon-rounded-big.png',
# 'math-image --path=TerdragonCurve --values=Lines,lines_type=rounded,midpoint_offset=.4 --figure=point --scale=16 --size=200 --offset=35,-30'],
# ['terdragon-rounded-6arm-big.png',
# 'math-image --path=TerdragonCurve,arms=6 --values=Lines,lines_type=rounded,midpoint_offset=.4 --figure=point --scale=10 --size=200'],
['terdragon-midpoint-6arm-big.png',
'math-image --path=TerdragonMidpoint,arms=6 --lines --figure=circle --scale=4 --size=200'],
['terdragon-midpoint-small.png',
'math-image --path=TerdragonMidpoint --lines --scale=2 --size=32 --offset=2,-9'],
['terdragon-midpoint-big.png',
'math-image --path=TerdragonMidpoint --lines --figure=circle --scale=8 --size=200 --offset=50,-50'],
['r5dragon-small.png',
'math-image --path=R5DragonCurve --lines --scale=4 --size=32 --offset=6,-5'],
['r5dragon-big.png',
'math-image --path=R5DragonCurve --lines --figure=point --scale=10 --size=200x200 --offset=20,45'],
['r5dragon-rounded-big.png',
'math-image --path=R5DragonCurve --values=Lines,lines_type=rounded,midpoint_offset=.6 --figure=point --scale=10 --size=200x200 --offset=20,45'],
['r5dragon-rounded-4arm-big.png',
'math-image --path=R5DragonCurve,arms=4 --values=Lines,lines_type=rounded,midpoint_offset=.6 --figure=point --scale=20 --size=200x200'],
['r5dragon-midpoint-small.png',
'math-image --path=R5DragonMidpoint --lines --scale=3 --size=32 --offset=3,-9'],
['r5dragon-midpoint-big.png',
'math-image --path=R5DragonMidpoint --lines --figure=point --scale=8 --size=200 --offset=65,-15'],
['r5dragon-midpoint-4arm-big.png',
'math-image --path=R5DragonMidpoint,arms=4 --lines --figure=point --scale=12 --size=200'],
['cubicbase-small.png',
'math-image --path=CubicBase --lines --scale=5 --size=32'],
['cubicbase-big.png',
'math-image --path=CubicBase --lines --scale=18 --size=200'],
['cubicbase-radix5-big.png',
'math-image --path=CubicBase,radix=5 --lines --scale=18 --size=200'],
['peano-small.png',
'math-image --path=PeanoCurve --lines --scale=3 --size=32'],
['peano-big.png',
'math-image --path=PeanoCurve --lines --scale=7 --size=192'],
['peano-radix7-big.png',
'math-image --path=PeanoCurve,radix=7 --values=Lines --scale=5 --size=192'],
['gray-code-small.png',
'math-image --path=GrayCode --lines --scale=6 --size=32'],
['gray-code-big.png',
'math-image --path=GrayCode --lines --scale=14 --size=226'],
['gray-code-radix4-big.png',
'math-image --path=GrayCode,radix=4 --lines --scale=14 --size=226'],
['zorder-small.png',
'math-image --path=ZOrderCurve --lines --scale=6 --size=32'],
['zorder-big.png',
'math-image --path=ZOrderCurve --lines --scale=14 --size=226'],
['zorder-radix5-big.png',
'math-image --path=ZOrderCurve,radix=5 --lines --scale=14 --size=226'],
['zorder-fibbinary.png',
'math-image --path=ZOrderCurve --values=Fibbinary --scale=1 --size=704x320'],
['wunderlich-serpentine-small.png',
'math-image --path=WunderlichSerpentine --lines --scale=4 --size=32'],
['wunderlich-serpentine-big.png',
'math-image --path=WunderlichSerpentine --lines --scale=7 --size=192'],
['wunderlich-serpentine-coil-big.png',
'math-image --path=WunderlichSerpentine,serpentine_type=coil --values=Lines --scale=7 --size=192'],
['wunderlich-serpentine-radix7-big.png',
'math-image --path=WunderlichSerpentine,radix=7 --values=Lines --scale=5 --size=192'],
['cretan-labyrinth-small.png',
'math-image --path=CretanLabyrinth --lines --scale=3 --size=32'],
['cretan-labyrinth-big.png',
'math-image --path=CretanLabyrinth --lines --scale=9 --size=185x195 --offset=5,0'],
['theodorus-small.png',
'math-image --path=TheodorusSpiral --lines --scale=3 --size=32'],
['theodorus-big.png',
'math-image --path=TheodorusSpiral --lines --scale=10 --size=200'],
['filled-rings-small.png',
'math-image --path=FilledRings --lines --scale=4 --size=32'],
['filled-rings-big.png',
'math-image --path=FilledRings --lines --scale=10 --size=200'],
['pixel-small.png',
'math-image --path=PixelRings --lines --scale=4 --size=32'],
['pixel-big.png',
'math-image --path=PixelRings --all --figure=circle --scale=10 --size=200',
border => 1 ],
['pixel-lines-big.png',
'math-image --path=PixelRings --lines --scale=10 --size=200'],
['staircase-small.png',
'math-image --path=Staircase --lines --scale=4 --size=32'],
['staircase-big.png',
'math-image --path=Staircase --lines --scale=12 --size=200x200'],
['staircase-alternating-square-small.png',
'math-image --path=StaircaseAlternating,end_type=square --lines --scale=4 --size=32'],
['staircase-alternating-big.png',
'math-image --path=StaircaseAlternating --lines --scale=12 --size=200x200'],
['staircase-alternating-square-big.png',
'math-image --path=StaircaseAlternating,end_type=square --lines --scale=12 --size=200x200'],
['cellular-rule-30-small.png',
'math-image --path=CellularRule,rule=30 --all --scale=2 --size=32'],
['cellular-rule-30-big.png',
'math-image --path=CellularRule,rule=30 --all --scale=4 --size=300x150'],
['cellular-rule-73-big.png',
'math-image --path=CellularRule,rule=73 --all --scale=4 --size=300x150'],
['cellular-rule190-small.png',
'math-image --path=CellularRule190 --all --scale=3 --size=32'],
['cellular-rule190-big.png',
'math-image --path=CellularRule190 --all --scale=4 --size=300x150'],
['cellular-rule190-mirror-big.png',
'math-image --path=CellularRule190,mirror=1 --all --scale=4 --size=300x150'],
['cellular-rule54-small.png',
'math-image --path=CellularRule54 --all --scale=3 --size=32'],
['cellular-rule54-big.png',
'math-image --path=CellularRule54 --all --scale=4 --size=300x150'],
['complexplus-small.png',
"math-image --path=ComplexPlus --all --scale=2 --size=32"],
['complexplus-big.png',
"math-image --path=ComplexPlus --all --scale=3 --size=200",
border => 1],
['complexplus-r2-small.png',
"math-image --path=ComplexPlus,realpart=2 --all --scale=2 --size=32"],
['complexplus-r2-big.png',
"math-image --path=ComplexPlus,realpart=2 --all --scale=1 --size=200",
border => 1],
['digit-groups-small.png',
"math-image --path=DigitGroups --expression='i<256?i:0' --scale=2 --size=32"],
# --foreground=red
['digit-groups-big.png',
"math-image --path=DigitGroups --expression='i<2048?i:0' --scale=3 --size=200",
border => 1],
['digit-groups-radix5-big.png',
"math-image --path=DigitGroups,radix=5 --expression='i<15625?i:0' --scale=3 --size=200",
border => 1],
['l-tiling-small.png',
'math-image --path=LTiling --all --scale=2 --size=32' ],
['l-tiling-big.png',
'math-image --path=LTiling --all --scale=10 --size=200',
border => 1 ],
['l-tiling-ends-big.png',
'math-image --path=LTiling,L_fill=ends --all --scale=10 --size=200',
border => 1],
['l-tiling-all-big.png',
'math-image --path=LTiling,L_fill=all --lines --scale=10 --size=200'],
['dragon-rounded-small.png',
'math-image --path=DragonRounded --lines --scale=2 --size=32 --offset=6,-3'],
['dragon-rounded-big.png',
'math-image --path=DragonRounded --lines --figure=point --scale=3 --size=200 --offset=-20,0'],
['dragon-rounded-3arm-big.png',
'math-image --path=DragonRounded,arms=3 --lines --figure=point --scale=3 --size=200'],
['dragon-midpoint-small.png',
'math-image --path=DragonMidpoint --lines --scale=3 --size=32 --offset=7,-6'],
['dragon-midpoint-big.png',
'math-image --path=DragonMidpoint --lines --figure=point --scale=8 --size=200 --offset=-10,50'],
['dragon-midpoint-4arm-big.png',
'math-image --path=DragonMidpoint,arms=4 --lines --figure=point --scale=8 --size=200'],
['dragon-small.png',
'math-image --path=DragonCurve --lines --scale=4 --size=32 --offset=6,0'],
['dragon-big.png',
'math-image --path=DragonCurve --lines --figure=point --scale=8 --size=250x200 --offset=-55,0'],
['cellular-rule57-small.png',
'math-image --path=CellularRule57 --all --scale=3 --size=32'],
['cellular-rule57-big.png',
'math-image --path=CellularRule57 --all --scale=4 --size=300x150'],
['cellular-rule57-mirror-big.png',
'math-image --path=CellularRule57,mirror=1 --all --scale=4 --size=300x150'],
['quadric-islands-small.png',
'math-image --path=QuadricIslands --lines --scale=4 --size=32'],
['quadric-islands-big.png',
'math-image --path=QuadricIslands --lines --scale=2 --size=200'],
['quadric-curve-small.png',
'math-image --path=QuadricCurve --lines --scale=2 --size=32'],
['quadric-curve-big.png',
'math-image --path=QuadricCurve --lines --scale=4 --size=300x200'],
['divisible-columns-small.png',
'math-image --path=DivisibleColumns --all --scale=3 --size=32'],
['divisible-columns-big.png',
'math-image --path=DivisibleColumns --all --scale=3 --size=200'],
['divisible-columns-proper-big.png',
'math-image --path=DivisibleColumns,divisor_type=proper --all --scale=3 --size=400x200'],
['vogel-small.png',
'math-image --path=VogelFloret --all --scale=3 --size=32'],
['vogel-big.png',
'math-image --path=VogelFloret --all --scale=4 --size=200'],
['vogel-sqrt2-big.png',
'math-image --path=VogelFloret,rotation_type=sqrt2 --all --scale=4 --size=200'],
['vogel-sqrt5-big.png',
'math-image --path=VogelFloret,rotation_type=sqrt5 --all --scale=4 --size=200'],
['anvil-small.png',
'math-image --path=AnvilSpiral --lines --scale=4 --size=32'],
['anvil-big.png',
'math-image --path=AnvilSpiral --lines --scale=13 --size=200'],
['anvil-wider4-big.png',
'math-image --path=AnvilSpiral,wider=4 --lines --scale=13 --size=200'],
['octagram-small.png',
'math-image --path=OctagramSpiral --lines --scale=4 --size=32'],
['octagram-big.png',
'math-image --path=OctagramSpiral --lines --scale=13 --size=200'],
['complexrevolving-small.png',
"math-image --path=ComplexRevolving --expression='i<64?i:0' --scale=2 --size=32"],
['complexrevolving-big.png',
"math-image --path=ComplexRevolving --expression='i<4096?i:0' --scale=2 --size=200"],
['fractions-tree-small.png',
'math-image --path=FractionsTree --values=LinesTree --scale=8 --size=32 --offset=-8,-12'],
['fractions-tree-big.png',
'math-image --path=FractionsTree --all --scale=3 --size=200'],
['fractions-tree-lines-kepler.png',
'math-image --path=FractionsTree,tree_type=Kepler --values=LinesTree --scale=20 --size=200'],
['factor-rationals-small.png',
'math-image --path=FactorRationals --lines --scale=6 --size=32 --offset=-4,-4'],
['factor-rationals-big.png',
'math-image --path=FactorRationals --lines --scale=15 --size=200'],
['ar2w2-small.png',
'math-image --path=AR2W2Curve --lines --scale=4 --size=32 --figure=point'],
['ar2w2-a1-big.png',
'math-image --path=AR2W2Curve --lines --scale=7 --size=225 --figure=point'],
['ar2w2-d2-big.png',
'math-image --path=AR2W2Curve,start_shape=D2 --lines --scale=7 --size=113 --figure=point'],
['ar2w2-b2-big.png',
'math-image --path=AR2W2Curve,start_shape=B2 --lines --scale=7 --size=113 --figure=point'],
['ar2w2-b1rev-big.png',
'math-image --path=AR2W2Curve,start_shape=B1rev --lines --scale=7 --size=113 --figure=point'],
['ar2w2-d1rev-big.png',
'math-image --path=AR2W2Curve,start_shape=D1rev --lines --scale=7 --size=113 --figure=point'],
['ar2w2-a2rev-big.png',
'math-image --path=AR2W2Curve,start_shape=A2rev --lines --scale=7 --size=113 --figure=point'],
['diagonal-rationals-small.png',
'math-image --path=DiagonalRationals --lines --scale=4 --size=32'],
['diagonal-rationals-big.png',
'math-image --path=DiagonalRationals --lines --scale=10 --size=200'],
['coprime-columns-small.png',
'math-image --path=CoprimeColumns --all --scale=3 --size=32'],
['coprime-columns-big.png',
'math-image --path=CoprimeColumns --all --scale=3 --size=200'],
['corner-small.png',
'math-image --path=Corner --lines --scale=4 --size=32'],
['corner-big.png',
'math-image --path=Corner --lines --scale=12 --size=200'],
['corner-wider4-big.png',
'math-image --path=Corner,wider=4 --lines --scale=12 --size=200'],
['kochel-small.png',
'math-image --path=KochelCurve --lines --scale=4 --size=32 --figure=point'],
['kochel-big.png',
'math-image --path=KochelCurve --lines --scale=7 --size=192 --figure=point'],
['beta-omega-small.png',
'math-image --path=BetaOmega --lines --scale=4 --size=32 --figure=point'],
['beta-omega-big.png',
'math-image --path=BetaOmega --lines --scale=7 --size=226 --figure=point'],
['mpeaks-small.png',
'math-image --path=MPeaks --lines --scale=4 --size=32'],
['mpeaks-big.png',
'math-image --path=MPeaks --lines --scale=13 --size=200x180'],
['hex-small.png',
'math-image --path=HexSpiral --lines --scale=3 --size=32'],
['hex-big.png',
'math-image --path=HexSpiral --lines --scale=13 --size=300x150'],
['hex-wider4-big.png',
'math-image --path=HexSpiral,wider=4 --lines --scale=13 --size=300x150'],
['hex-arms-small.png',
'math-image --path=HexArms --lines --scale=3 --size=32'],
['hex-arms-big.png',
'math-image --path=HexArms --lines --scale=10 --size=300x150'],
['hex-skewed-small.png',
'math-image --path=HexSpiralSkewed --lines --scale=3 --size=32'],
['hex-skewed-big.png',
'math-image --path=HexSpiralSkewed --lines --scale=13 --size=150'],
['hex-skewed-wider4-big.png',
'math-image --path=HexSpiralSkewed,wider=4 --lines --scale=13 --size=150'],
['fibonacci-word-fractal-small.png',
'math-image --path=FibonacciWordFractal --lines --scale=2 --size=32 --offset=2,2'],
['fibonacci-word-fractal-big.png',
'math-image --path=FibonacciWordFractal --lines --scale=2 --size=345x170'],
['corner-replicate-small.png',
'math-image --path=CornerReplicate --lines --scale=4 --size=32'],
['corner-replicate-big.png',
'math-image --path=CornerReplicate --lines --scale=10 --size=200'],
['aztec-diamond-rings-small.png',
'math-image --path=AztecDiamondRings --lines --scale=4 --size=32 --offset=3,3'],
['aztec-diamond-rings-big.png',
'math-image --path=AztecDiamondRings --lines --scale=13 --size=200x200'],
['diamond-spiral-small.png',
'math-image --path=DiamondSpiral --lines --scale=4 --size=32'],
['diamond-spiral-big.png',
'math-image --path=DiamondSpiral --lines --scale=13 --size=200x200'],
['square-replicate-small.png',
'math-image --path=SquareReplicate --lines --scale=4 --size=32'],
['square-replicate-big.png',
'math-image --path=SquareReplicate --lines --scale=10 --size=215'],
['gosper-replicate-small.png', # 7^2-1=48
"math-image --path=GosperReplicate --expression='i<48?i:0' --scale=2 --size=32"],
['gosper-replicate-big.png', # 7^4-1=16806
"math-image --path=GosperReplicate --expression='i<16806?i:0' --scale=1 --size=320x200"],
['gosper-side-small.png',
'math-image --path=GosperSide --lines --scale=3 --size=32 --offset=-13,-7'],
['gosper-side-big.png',
'math-image --path=GosperSide --lines --scale=1 --size=250x200 --offset=95,-95'],
['gosper-islands-small.png',
'math-image --path=GosperIslands --lines --scale=3 --size=32'],
['gosper-islands-big.png',
'math-image --path=GosperIslands --lines --scale=2 --size=250x200'],
['square-small.png',
'math-image --path=SquareSpiral --lines --scale=4 --size=32'],
['square-big.png',
'math-image --path=SquareSpiral --lines --scale=13 --size=200'],
['square-wider4-big.png',
'math-image --path=SquareSpiral,wider=4 --lines --scale=13 --size=253x200'],
['quintet-replicate-small.png',
"math-image --path=QuintetReplicate --expression='i<125?i:0' --scale=2 --size=32"],
['quintet-replicate-big.png',
"math-image --path=QuintetReplicate --expression='i<3125?i:0' --scale=2 --size=200"],
['quintet-curve-small.png',
'math-image --path=QuintetCurve --lines --scale=4 --size=32 --offset=-10,0 --figure=point'],
['quintet-curve-big.png',
'math-image --path=QuintetCurve --lines --scale=7 --size=200 --offset=-20,-70 --figure=point'],
['quintet-curve-4arm-big.png',
'math-image --path=QuintetCurve,arms=4 --lines --scale=7 --size=200 --figure=point'],
['quintet-centres-small.png',
'math-image --path=QuintetCentres --lines --scale=4 --size=32 --offset=-10,0 --figure=point'],
['quintet-centres-big.png',
'math-image --path=QuintetCentres --lines --scale=7 --size=200 --offset=-20,-70 --figure=point'],
['koch-squareflakes-inward-small.png',
'math-image --path=KochSquareflakes,inward=1 --lines --scale=2 --size=32'],
['koch-squareflakes-inward-big.png',
'math-image --path=KochSquareflakes,inward=1 --lines --scale=2 --size=150x150'],
['koch-squareflakes-small.png',
'math-image --path=KochSquareflakes --lines --scale=1 --size=32'],
['koch-squareflakes-big.png',
'math-image --path=KochSquareflakes --lines --scale=2 --size=150x150'],
['koch-snowflakes-small.png',
'math-image --path=KochSnowflakes --lines --scale=2 --size=32'],
['koch-snowflakes-big.png',
'math-image --path=KochSnowflakes --lines --scale=3 --size=200x150'],
['koch-peaks-small.png',
'math-image --path=KochPeaks --lines --scale=2 --size=32'],
['koch-peaks-big.png',
'math-image --path=KochPeaks --lines --scale=3 --size=200x100'],
['diamond-arms-small.png',
'math-image --path=DiamondArms --lines --scale=5 --size=32'],
['diamond-arms-big.png',
'math-image --path=DiamondArms --lines --scale=15 --size=150x150'],
['square-arms-small.png',
'math-image --path=SquareArms --lines --scale=3 --size=32'],
['square-arms-big.png',
'math-image --path=SquareArms --lines --scale=10 --size=150x150'],
['hept-skewed-small.png',
'math-image --path=HeptSpiralSkewed --lines --scale=4 --size=32'],
['hept-skewed-big.png',
'math-image --path=HeptSpiralSkewed --lines --scale=13 --size=200'],
['pent-small.png',
'math-image --path=PentSpiral --lines --scale=4 --size=32'],
['pent-big.png',
'math-image --path=PentSpiral --lines --scale=13 --size=200'],
['hypot-octant-small.png',
'math-image --path=HypotOctant --lines --scale=5 --size=32'],
['hypot-octant-big.png',
'math-image --path=HypotOctant --lines --scale=15 --size=200x150'],
['hypot-small.png',
'math-image --path=Hypot --lines --scale=6 --size=32'],
['hypot-big.png',
'math-image --path=Hypot --lines --scale=15 --size=200x150'],
['knight-small.png',
'math-image --path=KnightSpiral --lines --scale=7 --size=32'],
['knight-big.png',
'math-image --path=KnightSpiral --lines --scale=11 --size=197'],
['multiple-small.png',
'math-image --path=MultipleRings --lines --scale=4 --size=32'],
['multiple-big.png',
'math-image --path=MultipleRings --lines --scale=10 --size=200'],
['sacks-small.png',
'math-image --path=SacksSpiral --lines --scale=5 --size=32'],
['sacks-big.png',
'math-image --path=SacksSpiral --lines --scale=10 --size=200'],
['archimedean-small.png',
'math-image --path=ArchimedeanChords --lines --scale=5 --size=32'],
['archimedean-big.png',
'math-image --path=ArchimedeanChords --lines --scale=10 --size=200'],
) {
my ($filename, $command, %option) = @$elem;
if ($seen_filename{$filename}++) {
die "Duplicate filename $filename";
}
if (ref $command) {
&$command ($tempfile);
} else {
$command .= " --png >$tempfile";
### $command
my $status = system $command;
if ($status) {
die "Exit $status";
}
}
if ($option{'border'}) {
png_border($tempfile);
}
pngtextadd($tempfile, 'Author', 'Kevin Ryde');
pngtextadd($tempfile, 'Generator',
'Math-PlanePath tools/gallery.pl running math-image');
{
my $title = $option{'title'};
if (! defined $title) {
$command =~ /--path=([^ ]+)/
or die "Oops no --path in command: $command";
$title = $1;
if ($command =~ /--values=(Fibbinary)/) {
$title .= " $1";
}
}
pngtextadd ($tempfile, 'Title', $title);
}
system ("optipng -quiet -o2 $tempfile");
my $targetfile = "$target_dir/$filename";
if (File::Compare::compare($tempfile,$targetfile) == 0) {
print "Unchanged $filename\n";
} else {
print "Update $filename\n";
File::Copy::copy($tempfile,$targetfile);
}
if ($filename !~ /small/) {
$big_bytes += -s $targetfile;
}
}
foreach my $filename (<*.png>) {
$filename =~ s{.*/}{};
if (! $seen_filename{$filename}) {
print "leftover file: $filename\n";
}
}
my $gallery_html_filename = "$target_dir/gallery.html";
my $gallery_html_bytes = -s $gallery_html_filename;
my $total_gallery_bytes = $big_bytes + $gallery_html_bytes;
print "total gallery bytes $total_gallery_bytes ($gallery_html_bytes html, $big_bytes \"big\" images)\n";
exit 0;
# draw a 1-pixel black border around the png image in $filename
sub png_border {
my ($filename) = @_;
my $image = Image::Base::GD->new(-file => $filename);
$image->rectangle (0,0,
$image->get('-width') - 1,
$image->get('-height') - 1,
'black');
$image->save;
}
# add text to the png image in $filename
sub pngtextadd {
my ($filename, $keyword, $value) = @_;
system('pngtextadd', "--keyword=$keyword", "--text=$value", $tempfile) == 0
or die "system(pngtextadd)";
}
sub special_chan_rows {
my ($filename) = @_;
my $scale = 8;
my $width = 400;
my $height = 200;
my $margin = int($scale * .2);
my $xhi = int($width/$scale) + 3;
my $yhi = int($height/$scale) + 3;
require Geometry::AffineTransform;
my $affine = Geometry::AffineTransform->new;
$affine->scale ($scale, -$scale);
$affine->translate (-$scale+$margin, $height-1 - (-$scale+$margin));
{
my ($x,$y) = $affine->transform (0,0);
### $x
### $y
}
require Image::Base::GD;
my $image = Image::Base::GD->new (-width => $width, -height => $height);
$image->rectangle (0,0, $width-1,$height-1, 'black');
require Math::PlanePath::ChanTree;
my $path = Math::PlanePath::ChanTree->new (digit_order => 'LtoH',
reduced => 0);
foreach my $y (0 .. $yhi) {
foreach my $x (0 .. $xhi) {
my $n = $path->xy_to_n($x,$y) // next;
next unless $path->tree_n_root($n) == 0; # first root only
my $depth = $path->tree_n_to_depth($n);
foreach my $n2 ($n + 1, $n - 1) {
next unless $n2 >= 1;
next unless $path->tree_n_to_depth($n2) == $depth; # within same depth
next unless $path->tree_n_root($n2) == 0; # first root only
my ($x2,$y2) = $path->n_to_xy($n2);
my ($sx1,$sy1) = $affine->transform($x,$y);
my ($sx2,$sy2) = $affine->transform($x2,$y2);
_image_line_clipped ($image, $sx1,$sy1, $sx2,$sy2,
$width,$height, 'white');
}
}
}
$image->save($filename);
}
sub special_sb_rows {
my ($filename) = @_;
my $scale = 14;
my $width = 200;
my $height = 200;
my $margin = int($scale * .2);
my $xhi = int($width/$scale) + 3;
my $yhi = int($height/$scale) + 3;
require Geometry::AffineTransform;
my $affine = Geometry::AffineTransform->new;
$affine->scale ($scale, -$scale);
$affine->translate (-$scale+$margin, $height-1 - (-$scale+$margin));
{
my ($x,$y) = $affine->transform (0,0);
### $x
### $y
}
require Image::Base::GD;
my $image = Image::Base::GD->new (-width => $width, -height => $height);
$image->rectangle (0,0, $width-1,$height-1, 'black');
require Math::PlanePath::RationalsTree;
my $path = Math::PlanePath::RationalsTree->new;
foreach my $y (0 .. $yhi) {
foreach my $x (0 .. $xhi) {
my $n = $path->xy_to_n($x,$y) // next;
my $depth = $path->tree_n_to_depth($n);
foreach my $n2 ($n + 1, $n - 1) {
next unless $n2 >= 1;
next unless $path->tree_n_to_depth($n2) == $depth;
my ($x2,$y2) = $path->n_to_xy($n2);
my ($sx1,$sy1) = $affine->transform($x,$y);
my ($sx2,$sy2) = $affine->transform($x2,$y2);
_image_line_clipped ($image, $sx1,$sy1, $sx2,$sy2,
$width,$height, 'white');
}
}
}
$image->save($filename);
}
sub _image_line_clipped {
my ($image, $x1,$y1, $x2,$y2, $width,$height, $colour) = @_;
### _image_line_clipped(): "$x1,$y1 $x2,$y2 ${width}x${height}"
if (($x1,$y1, $x2,$y2) = line_clipper ($x1,$y1, $x2,$y2, $width,$height)) {
### clipped draw: "$x1,$y1 $x2,$y2"
$image->line ($x1,$y1, $x2,$y2, $colour);
return 1;
} else {
return 0;
}
}
sub line_clipper {
my ($x1,$y1, $x2,$y2, $width, $height) = @_;
return if ($x1 < 0 && $x2 < 0)
|| ($x1 >= $width && $x2 >= $width)
|| ($y1 < 0 && $y2 < 0)
|| ($y1 >= $height && $y2 >= $height);
my $x1new = $x1;
my $y1new = $y1;
my $x2new = $x2;
my $y2new = $y2;
my $xlen = ($x1 - $x2);
my $ylen = ($y1 - $y2);
if ($x1new < 0) {
$x1new = 0;
$y1new = floor (0.5 + ($y1 * (-$x2)
+ $y2 * ($x1)) / $xlen);
### x1 neg: "y1new to $x1new,$y1new"
} elsif ($x1new >= $width) {
$x1new = $width-1;
$y1new = floor (0.5 + ($y1 * ($x1new-$x2)
+ $y2 * ($x1 - $x1new)) / $xlen);
### x1 big: "y1new to $x1new,$y1new"
}
if ($y1new < 0) {
$y1new = 0;
$x1new = floor (0.5 + ($x1 * (-$y2)
+ $x2 * ($y1)) / $ylen);
### y1 neg: "x1new to $x1new,$y1new left ".($y1new-$y2)." right ".($y1-$y1new)
### x1new to: $x1new
} elsif ($y1new >= $height) {
$y1new = $height-1;
$x1new = floor (0.5 + ($x1 * ($y1new-$y2)
+ $x2 * ($y1 - $y1new)) / $ylen);
### y1 big: "x1new to $x1new,$y1new left ".($y1new-$y2)." right ".($y1-$y1new)
}
if ($x1new < 0 || $x1new >= $width) {
### x1new outside
return;
}
if ($x2new < 0) {
$x2new = 0;
$y2new = floor (0.5 + ($y2 * ($x1)
+ $y1 * (-$x2)) / $xlen);
### x2 neg: "y2new to $x2new,$y2new"
} elsif ($x2new >= $width) {
$x2new = $width-1;
$y2new = floor (0.5 + ($y2 * ($x1-$x2new)
+ $y1 * ($x2new-$x2)) / $xlen);
### x2 big: "y2new to $x2new,$y2new"
}
if ($y2new < 0) {
$y2new = 0;
$x2new = floor (0.5 + ($x2 * ($y1)
+ $x1 * (-$y2)) / $ylen);
### y2 neg: "x2new to $x2new,$y2new"
} elsif ($y2new >= $height) {
$y2new = $height-1;
$x2new = floor (0.5 + ($x2 * ($y1-$y2new)
+ $x1 * ($y2new-$y2)) / $ylen);
### y2 big: "x2new $x2new,$y2new"
}
if ($x2new < 0 || $x2new >= $width) {
### x2new outside
return;
}
return ($x1new,$y1new, $x2new,$y2new);
}
Math-PlanePath-113/tools/ar2w2-curve-table.pl 0000644 0001750 0001750 00000027637 12161517106 016557 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'min','max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub min_maybe {
return min(grep {defined} @_);
}
sub max_maybe {
return max(grep {defined} @_);
}
my $table_total = 0;
sub print_table {
my ($name, $aref) = @_;
$table_total += scalar(@$aref);
print "my \@$name\n = (";
my $entry_width = max (map {defined $_ ? length : 0} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15) {
print "\n ";
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
sub print_table12 {
my ($name, $aref) = @_;
$table_total += scalar(@$aref);
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 12) == 11) {
my $state = ($i-11)/3;
print " # 3* $state";
print "\n ".(" " x length($name));
} elsif (($i % 3) == 2) {
print " ";
}
}
}
}
sub make_state {
my ($part, $rot, $rev) = @_;
$rot %= 4;
return 4*($rot + 4*($rev + 2*$part));
}
my @part_name = ('A1','A2',
'B1','B2',
'C1','C2',
'D1','D2');
my @rev_name = ('','rev');
sub state_string {
my ($state) = @_;
my $digit = $state % 4; $state = int($state/4);
my $rot = $state % 4; $state = int($state/4);
my $rev = $state % 2; $state = int($state/2);
my $part = $state;
return "part=$part_name[$part]$rev_name[$rev] rot=$rot digit=$digit";
}
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @yx_to_digit;
my @min_digit;
my @max_digit;
use constant A1 => 0;
use constant A2 => 1;
use constant B1 => 2;
use constant B2 => 3;
use constant C1 => 4;
use constant C2 => 5;
use constant D1 => 6;
use constant D2 => 7;
foreach my $part (A1, A2, B1, B2, C1, C2, D1, D2) {
foreach my $rot (0, 1, 2, 3) {
foreach my $rev (0, 1) {
my $state = make_state ($part, $rot, $rev);
foreach my $orig_digit (0, 1, 2, 3) {
my $digit = $orig_digit;
if ($rev) {
$digit = 3-$digit;
}
my $xo = 0;
my $yo = 0;
my $new_part = $part;
my $new_rot = $rot;
my $new_rev = $rev;
if ($part == A1) {
if ($digit == 0) {
$new_part = D2;
} elsif ($digit == 1) {
$xo = 1;
$new_part = B1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 2) {
$yo = 1;
$new_part = C1;
$new_rot = $rot + 1;
} elsif ($digit == 3) {
$xo = 1;
$yo = 1;
$new_part = B2;
$new_rev ^= 1;
$new_rot = $rot + 2;
}
} elsif ($part == A2) {
if ($digit == 0) {
$new_part = B1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = C2;
} elsif ($digit == 2) {
$xo = 1;
$new_part = B2;
$new_rev ^= 1;
$new_rot = $rot + 2;
} elsif ($digit == 3) {
$xo = 1;
$yo = 1;
$new_part = D1;
$new_rot = $rot + 1;
}
} elsif ($part == B1) {
if ($digit == 0) {
$new_part = D1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = C2;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = B1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = B2;
$new_rev ^= 1;
$new_rot = $rot + 1;
}
} elsif ($part == B2) {
if ($digit == 0) {
$new_part = B1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = B2;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = C1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = D2;
$new_rev ^= 1;
$new_rot = $rot + 1;
}
} elsif ($part == C1) {
if ($digit == 0) {
$new_part = A2;
} elsif ($digit == 1) {
$yo = 1;
$new_part = B1;
$new_rot = $rot + 1;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = A1;
$new_rot = $rot - 1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = B2;
$new_rev ^= 1;
$new_rot = $rot + 1;
}
} elsif ($part == C2) {
if ($digit == 0) {
$new_part = B1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = A2;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = B2;
$new_rot = $rot - 1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = A1;
$new_rot = $rot - 1;
}
} elsif ($part == D1) {
if ($digit == 0) {
$new_part = D1;
$new_rev ^= 1;
$new_rot = $rot - 1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = A2;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = C2;
$new_rot = $rot - 1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = A2;
$new_rot = $rot - 1;
}
} elsif ($part == D2) {
if ($digit == 0) {
$new_part = A1;
} elsif ($digit == 1) {
$yo = 1;
$new_part = C1;
$new_rot = $rot + 1;
} elsif ($digit == 2) {
$xo = 1;
$yo = 1;
$new_part = A1;
$new_rot = $rot - 1;
} elsif ($digit == 3) {
$xo = 1;
$new_part = D2;
$new_rev ^= 1;
$new_rot = $rot + 1;
}
} else {
die;
}
### base: "$xo, $yo"
if ($rot & 2) {
$xo ^= 1;
$yo ^= 1;
}
if ($rot & 1) {
($xo,$yo) = ($yo^1,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$yx_to_digit[$state + $yo*2 + $xo] = $orig_digit;
my $next_state = make_state
($new_part, $new_rot, $new_rev);
$next_state[$state+$orig_digit] = $next_state;
}
foreach my $x1pos (0 .. 1) {
foreach my $x2pos ($x1pos .. 1) {
my $xr = ($x1pos ? 2 : $x2pos ? 1 : 0);
### $xr
foreach my $y1pos (0 .. 1) {
foreach my $y2pos ($y1pos .. 1) {
my $yr = ($y1pos ? 6 : $y2pos ? 3 : 0);
### $yr
my $min_digit = undef;
my $max_digit = undef;
foreach my $digit (0 .. 3) {
my $x = $digit_to_x[$state+$digit];
my $y = $digit_to_y[$state+$digit];
next unless $x >= $x1pos;
next unless $x <= $x2pos;
next unless $y >= $y1pos;
next unless $y <= $y2pos;
$min_digit = min_maybe($digit,$min_digit);
$max_digit = max_maybe($digit,$max_digit);
}
my $key = 3*$state + $xr + $yr;
### $key
if (defined $min_digit[$key]) {
die "oops min_digit[] already: state=$state key=$key y1p=$y1pos y2p=$y2pos value=$min_digit[$key], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
}
}
}
}
}
sub check_used {
my @pending_state = @_;
my $count = 0;
my @seen_state;
my $depth = 1;
while (@pending_state) {
my $state = pop @pending_state;
$count++;
### consider state: $state
foreach my $digit (0 .. 3) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
for (my $state = 0; $state < @next_state; $state += 4) {
if (! defined $seen_state[$state]) { $seen_state[$state] = 'none'; }
my $str = state_string($state);
print "# used state $state depth $seen_state[$state] $str\n";
}
print "used state count $count\n";
}
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("yx_to_digit", \@yx_to_digit);
print_table12 ("min_digit", \@min_digit);
print_table12 ("max_digit", \@max_digit);
print "# state length ",scalar(@next_state)," in each of 4 tables\n";
print "# grand total $table_total\n";
print "\n";
{
my %seen;
my @pending;
for (my $state = 0; $state < @next_state; $state += 4) {
push @pending, $state;
}
while (@pending) {
my $state = shift @pending;
next if $seen{$state}++;
next if $digit_to_x[$state] != 0 || $digit_to_y[$state] != 0;
my $next = $next_state[$state];
if ($next_state[$next] == $state) {
print "# cycle $state/$next ",state_string($state)," <-> ",state_string($next),"\n";
unshift @pending, $next;
}
}
print "#\n";
}
{
my $a1 = make_state(A1,0,0);
my $d2 = make_state(D2,0,0);
my $d1rev = make_state(D1,3,1);
my $a2rev = make_state(A2,2,1);
my $b2 = make_state(B2,0,0);
my $b1rev3 = make_state(B1,-1,1);
my $b1rev = make_state(B1,0,1);
my $b2_1 = make_state(B2,1,0);
my $str = <<"HERE";
my %start_state = (A1 => [$a1, $d2],
D2 => [$d2, $a1],
B2 => [$b2, $b1rev3],
B1rev => [$b1rev3, $b2],
D1rev => [$d1rev, $a2rev],
A2rev => [$a2rev, $d1rev],
);
HERE
print $str;
my %start_state = eval "$str; %start_state";
foreach my $elem (values %start_state) {
my ($s1, $s2) = @$elem;
$next_state[$s1]==$s2 or die;
$next_state[$s2]==$s1 or die;
$digit_to_x[$s1]==0 or die "$s1 not at 0,0";
$digit_to_y[$s1]==0 or die;
$digit_to_x[$s2]==0 or die;
$digit_to_y[$s2]==0 or die;
}
}
# print "# state A1=",make_state(A1,0,0),"\n";
# print "# state D2=",make_state(D2,0,0),"\n";
# print "# state D1=",make_state(D1,0,0),"\n";
# print "from A1/D2\n";
# check_used (make_state(A1,0,0), make_state(D2,0,0));
# print "from D1\n";
# check_used (make_state(D1,0,0));
{
print "\n";
require Graph::Easy;
my $g = Graph::Easy->new;
for (my $state = 0; $state < scalar(@next_state); $state += 4) {
my $next = $next_state[$state];
$g->add_edge("$state: ".state_string($state),
"$next: ".state_string($next));
}
print $g->as_ascii();
}
exit 0;
Math-PlanePath-113/tools/r5dragon-midpoint-offset.pl 0000644 0001750 0001750 00000004211 12201363223 020212 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use Math::PlanePath::R5DragonMidpoint;
# uncomment this to run the ### lines
#use Smart::Comments;
my $path = Math::PlanePath::R5DragonMidpoint->new (arms => 1);
my @yx_to_digdxdy;
foreach my $n (0 .. 5**10) {
my ($x,$y) = $path->n_to_xy($n);
my $digit = $n % 5;
my $to_n = ($n-$digit)/5;
my ($to_x,$to_y) = $path->n_to_xy($to_n);
# (x+iy)*(1+2i) = x-2y + 2x+y
($to_x,$to_y) = ($to_x-2*$to_y, 2*$to_x+$to_y);
my $dx = $to_x - $x;
my $dy = $to_y - $y;
my $k = 3*(10*($y%10) + ($x%10));
my $v0 = $digit;
my $v1 = $dx;
my $v2 = $dy;
if (defined $yx_to_digdxdy[$k+0] && $yx_to_digdxdy[$k+0] != $v0) {
die "diff v0 $yx_to_digdxdy[$k+0] $v0 k=$k n=$n";
}
if (defined $yx_to_digdxdy[$k+1] && $yx_to_digdxdy[$k+1] != $v1) {
die "diff v1 $yx_to_digdxdy[$k+1] $v1 k=$k n=$n";
}
if (defined $yx_to_digdxdy[$k+2] && $yx_to_digdxdy[$k+2] != $v2) {
die "diff v2 $yx_to_digdxdy[$k+2] $v2 k=$k n=$n";
}
$yx_to_digdxdy[$k+0] = $v0;
$yx_to_digdxdy[$k+1] = $v1;
$yx_to_digdxdy[$k+2] = $v2;
}
print_table(\@yx_to_digdxdy);
sub print_table {
my ($aref) = @_;
print "(";
for (my $i = 0; $i < @$aref; ) {
my $v0 = $aref->[$i++] // 'undef';
my $v1 = $aref->[$i++] // 'undef';
my $v2 = $aref->[$i++] // 'undef';
my $str = "$v0,$v1,$v2";
if ($i != $#$aref) { $str .= ", " }
printf "%-9s", $str;
if (($i % (3*5)) == 0) { print "\n " }
}
print ");\n";
}
exit 0;
Math-PlanePath-113/tools/wunderlich-meander-table.pl 0000644 0001750 0001750 00000015535 11660132465 020253 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min','max';
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined && length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*d", $entry_width, $aref->[$i];
if ($i == $#$aref) {
print "); # ",$i-8,"\n";
} else {
print ",";
if (($i % 9) == 8) {
print " # ".($i-8);
}
if (($i % 9) == 8) {
print "\n ".(" " x length($name));
} elsif (($i % 3) == 2) {
print " ";
}
}
}
}
sub print_table36 {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {defined && length} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*d", $entry_width, $aref->[$i];
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 36) == 5) {
print " # ".($i-5);
}
if (($i % 6) == 5) {
print "\n ".(" " x length($name));
} elsif (($i % 6) == 5) {
print " ";
}
}
}
}
sub make_state {
my ($transpose, $rot) = @_;
$transpose %= 2;
$rot %= 4;
($rot % 2) == 0 or die;
$rot /= 2;
return 9*($rot + 2*$transpose);
}
# x__ 0
# xx_ 1
# xxx 2
# _xx 3
# __x 4
# _x_ 5
my @r_to_cover = ([1,0,0],
[1,1,0],
[1,1,1],
[0,1,1],
[0,0,1],
[0,1,0]);
my @reverse_range = (4,3,2,1,0,5);
my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;
my @min_digit;
my @max_digit;
# 8 5-- 4
# | | |
# 7-- 6 3
# |
# 0-- 1-- 2
#
foreach my $transpose (0, 1) {
foreach my $rot (0, 2) {
my $state = make_state ($transpose, $rot);
foreach my $orig_digit (0 .. 8) {
my $digit = $orig_digit;
my $xo;
my $yo;
my $new_rot = $rot;
my $new_transpose = $transpose;
if ($digit == 0) {
$xo = 0;
$yo = 0;
$new_transpose ^= 1;
} elsif ($digit == 1) {
$xo = 1;
$yo = 0;
$new_transpose ^= 1;
} elsif ($digit == 2) {
$xo = 2;
$yo = 0;
} elsif ($digit == 3) {
$xo = 2;
$yo = 1;
} elsif ($digit == 4) {
$xo = 2;
$yo = 2;
} elsif ($digit == 5) {
$xo = 1;
$yo = 2;
$new_rot = $rot + 2;
} elsif ($digit == 6) {
$xo = 1;
$yo = 1;
$new_transpose ^= 1;
$new_rot = $rot + 2;
} elsif ($digit == 7) {
$xo = 0;
$yo = 1;
$new_transpose ^= 1;
$new_rot = $rot + 2;
} elsif ($digit == 8) {
$xo = 0;
$yo = 2;
} else {
die;
}
### base: "$xo, $yo"
if ($transpose) {
($xo,$yo) = ($yo,$xo);
}
if ($rot & 2) {
$xo = 2 - $xo;
$yo = 2 - $yo;
}
if ($rot & 1) {
($xo,$yo) = (2-$yo,$xo);
}
### rot to: "$xo, $yo"
$digit_to_x[$state+$orig_digit] = $xo;
$digit_to_y[$state+$orig_digit] = $yo;
$xy_to_digit[$state + 3*$xo + $yo] = $orig_digit;
my $next_state = make_state ($new_transpose, $new_rot);
$next_state[$state+$orig_digit] = $next_state;
}
foreach my $xrange (0 .. 5) {
foreach my $yrange (0 .. 5) {
my $xr = $xrange;
my $yr = $yrange;
my $bits = $xr + 6*$yr; # before transpose etc
my $key = 4*$state + $bits;
### assert: (4*$state % 36) == 0
if ($rot & 1) {
($xr,$yr) = ($yr,$reverse_range[$xr]);
}
if ($rot & 2) {
$xr = $reverse_range[$xr];
$yr = $reverse_range[$yr];
}
if ($transpose) {
($xr,$yr) = ($yr,$xr);
}
# now xr,yr plain unrotated etc
my $min_digit = 8;
my $max_digit = 0;
foreach my $digit (0 .. 8) {
my $x = $digit_to_x[$digit];
my $y = $digit_to_y[$digit];
next unless $r_to_cover[$xr]->[$x];
next unless $r_to_cover[$yr]->[$y];
$min_digit = min($digit,$min_digit);
$max_digit = max($digit,$max_digit);
}
### min/max: "state=$state 4*state=".(4*$state)." bits=$bits key=$key"
if (defined $min_digit[$key]) {
die "oops min_digit[] already: state=$state bits=$bits value=$min_digit[$state+$bits], new=$min_digit";
}
$min_digit[$key] = $min_digit;
$max_digit[$key] = $max_digit;
}
}
### @min_digit
}
}
print_table ("next_state", \@next_state);
print_table ("digit_to_x", \@digit_to_x);
print_table ("digit_to_y", \@digit_to_y);
print_table ("xy_to_digit", \@xy_to_digit);
print_table36 ("min_digit", \@min_digit);
print_table36 ("max_digit", \@max_digit);
print "# transpose state ",make_state(1,0),"\n";
print "# state length ",scalar(@next_state)," in each of 4 tables\n";
print "# min/max length ",scalar(@min_digit)," in each of 2 tables\n\n";
### @next_state
### @digit_to_x
### @digit_to_y
### @xy_to_digit
### next_state length: scalar(@next_state)
{
my @pending_state = (0);
my $count = 0;
my @seen_state;
my $depth = 1;
$seen_state[0] = $depth;
while (@pending_state) {
my $state = pop @pending_state;
$count++;
### consider state: $state
foreach my $digit (0 .. 8) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
for (my $state = 0; $state < @next_state; $state += 9) {
print "# used state $state depth ".($seen_state[$state]||0)."\n";
}
print "used state count $count\n";
}
print "\n";
exit 0;
Math-PlanePath-113/Changes 0000644 0001750 0001750 00000034644 12255673477 013227 0 ustar gg gg Copyright 2010, 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option)
any later version.
Math-PlanePath 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 Math-PlanePath. If not, see .
Version 113, December 2013
- PythagoreanTree new tree_type="UArD", digit_order="LtoH"
- PlanePathCoord new coordinate_type "MinAbs","MaxAbs"
Version 112, December 2013
- PythagoreanTree new tree_type="UMT"
Version 111, November 2013
- FactorRationals new factor_coding "odd/even","negabinary","revbinary"
- new sumabsxy_minimum(), sumabsxy_maximum(), absdiffxy_minimum(),
absdiffxy_maximum()
Version 110, August 2013
- PlanePathTurn new turn_type "SLR","SRL"
Version 109, August 2013
- TerdragonCurve correction to dx_minimum()
- TerdragonMidpoint correction to dx_maximum()
Version 108, July 2013
- new tree_n_to_subheight()
- PlanePathCoord new coordinate_type "SubHeight"
- tests skip some 64-bit perl 5.6.2 dodginess in "%" operator
Version 107, July 2013
- PentSpiral,PentSpiralSkewed,HeptSpiralSkewed,OctagramSpiral,
Staircase,StaircaseAlternating new parameter n_start
- FilledRings fix parameter_info_array() missing n_start
- StaircaseAlternating fix parameter_info_array() missing end_type
Version 106, June 2013
- new methods tree_n_root(), tree_num_roots(), tree_root_n_list(),
tree_depth_to_n_range(), tree_depth_to_width(), tree_num_children_list(),
dsumxy_minimum(),dsumxy_maximum(), ddiffxy_minimum(),ddiffxy_maximum()
- PyramidSpiral new parameter n_start
- PlanePathCoord new coordinate_type "RootN"
Version 105, June 2013
- PlanePathCoord new coordinate_type "NumSiblings"
Version 104, May 2013
- new method n_to_radius()
Version 103, May 2013
- UlamWarburton new parts=2,1
- PythagoreanTree new coordinates="SM","SC","MC"
Version 102, April 2013
- new sumxy_minimum(),sumxy_maximum(), diffxy_minimum(),diffxy_maximum(),
- PlanePathDelta new delta_type=>"dSumAbs"
Version 101, April 2013
- MultipleRings fixes for ring_shape=polygon xy_to_n(), rect_to_n_range()
- CellularRule,CellularRule54,CellularRule57,CellularRule190
new parameter n_start
- DiagonalRationals new parameter direction=up
Version 100, March 2013
- new absdx_minimum(),absdx_maximum(), absdy_minimum(),absdy_maximum(),
dir_minimum_dxdy(),dir_maximum_dxdy()
- AztecDiamondRings new parameter n_start
- TriangleSpiralSkewed new parameter skew=right,up,down
- WythoffArray new parameters x_start,y_start
- PlanePathDelta new delta_type=>"dAbsDiff"
Version 99, February 2013
- oops, correction to IntXY on negatives
Version 98, February 2013
- CoprimeColumns,DiagonalRationals,DivisibleColumns new n_start parameter
- PlanePathCoord new coordinate_type "IntXY"
Version 97, January 2013
- new tree_num_children_minimum(), tree_num_children_maximum()
Version 96, January 2013
- AnvilSpiral,HexSpiral,HexSpiralSkewed new n_start, which was in
parameter_info but did nothing
- FilledRings new n_start parameter
Version 95, December 2012
- new tree_any_leaf()
- PythagoreanTree new coordinates="AC" and "BC"
Version 94, December 2012
- new rsquared_minimum(), rsquared_maximum()
- PlanePathCoord new coordinate_type "IsLeaf","IsNonLeaf"
- ImaginaryHalf new option "digit_order"
- Math::PlanePath::Base::Generic new parameter_info_nstart1()
Version 93, November 2012
- new xy_is_visited()
- PlanePathCoord new coordinate_type "Min","Max","BitAnd","BitOr","BitXor"
Version 92, October 2012
- new x_minimum(),x_maximum(), y_minimum(),y_maximum(),
dx_minimum(),dx_maximum(), dy_minimum(),dy_maximum()
Version 91, October 2012
- new tree_depth_to_n(), tree_depth_to_n_end()
- RationalsTree new tree_type "HCS"
- UlamWarburton,UlamWarburtonQuarter new "n_start" parameter
- PlanePathN new line_type=>"Depth_start","Depth_end"
- Math::PlanePath::Base::Digits new bit_split_lowtohigh()
Version 90, October 2012
- new CfracDigits, ChanTree
- tree_n_num_children() return undef when no such N
- Diagonals new x_start,y_start parameters
- PlanePathCoord new coordinate_type "GCD"
Version 89, September 2012
- RationalsTree new tree_type=L
Version 88, September 2012
- new DekkingCurve, DekkingCentres
- new tree_n_to_depth()
- PlanePathCoord new coordinate_type "Depth"
- DiamondSpiral new "n_start" parameter
Version 87, August 2012
- new tree_n_num_children()
- PlanePathCoord new coordinate_type "NumChildren"
- SierpinskiArrowhead,SierpinskiArrowheadCentres new parameter
align=right,left,diagonal
- Rows,Columns new "n_start" parameter
- KnightSpiral,PentSpiral,SierpinskiCurve fixes for n_to_xy() on
some fractional N
Version 86, August 2012
- Diagonals,DiagonalsOctant,DiagonalsAlternating,PyramidRows,PyramidSides,
Corner new "n_start" parameter
Version 85, August 2012
- SquareSpiral new "n_start" parameter
- PlanePathDelta new delta_type=>"AbsdX","AbsdY"
Version 84, August 2012
- PyramidRows new "align" parameter
Version 83, July 2012
- new n_to_dxdy()
- SierpinskiTriangle new parameter align=right,left,diagonal
- SierpinskiTriangle,TriangleSpiral,TriangleSpiralSkewed,Hypot new
"n_start" parameter
- PlanePathDelta new delta_type=>"dDiffYX"
- PlanePathN new line_type=>"Diagonal_NW","Diagonal_SW","Diagonal_SE"
- Math::PlanePath::Base::Digits new digit_join_lowtohigh()
- new Math::PlanePath::Base::Generic round_nearest()
Version 82, July 2012
- new tree_n_children(), tree_n_parent()
- PlanePathDelta new delta_type=>"dDiffXY"
- ImaginaryBase,ImaginaryHalf rect_to_n_range() exact
- new Math::PlanePath::Base::Digits round_down_pow(),
digit_split_lowtohigh(), parameter_info_array(), parameter_info_radix2()
Version 81, July 2012
- TriangularHypot new points=hex,hex_rotated,hex_centred
Version 80, July 2012
- new AlternatePaperMidpoint
- AlternatePaper new "arms"
- GreekKeySpiral new "turns"
- ComplexPlus, Flowsnake, FlowsnakeCentres, TerdragonMidpoint,
TerdragonRounded, R5DragonMidpoint fix for arms>1 fractional N
Version 79, June 2012
- TriangularHypot new option points=odd,even
Version 78, June 2012
- new WythoffArray, PowerArray
- GcdRationals new option pairs_order
- Hypot,HypotOctant new option points=odd,even
- Diagonals new options direction=up,down
Version 77, June 2012
- new DiagonalsOctant
Version 76, May 2012
- tests allow for as_float() only in recent Math::BigRat
Version 75, May 2012
- new CubicBase, CCurve, R5DragonCurve, R5DragonMidpoint, TerdragonRounded
- MultipleRings new ring_shape=>"polygon"
- PlanePathDelta new delta_type=>"dSum"
- fix TheodorusSpiral n_to_rsquared() on fractional N
Version 74, May 2012
- new ImaginaryBase
- new method n_to_rsquared()
- PlanePathN new line_type X_neg,Y_neg
- fix ImaginaryBase xy_to_n() possible infloop on floating point rounding
- fix TerdragonMidpoint xy_to_n() undef on points outside requested arms
Version 73, April 2012
- new GrayCode, SierpinskiCurveStair, WunderlichSerpentine
- fix GcdRationals xy_to_n() on BigInt
- PlanePathCoord new coordinate_type "SumAbs","TRadius","TRSquared"
Version 72, March 2012
- PlanePathTurn new turn_type "Right"
Version 71, February 2012
- new FilledRings
- misc fixes for Math::NumSeq::PlanePathCoord etc values_min etc
Version 70, February 2012
- TheodorusSpiral fix n_to_xy() position saving
- StaircaseAlternating new end_type=>"square"
Version 69, February 2012
- new Math::NumSeq::PlanePathTurn
- Math::NumSeq::PlanePathN new pred()
Version 68, February 2012
- new xy_to_n_list()
- new CretanLabyrinth
Version 67, February 2012
- oops, DragonMidpoint,DragonRounded xy_to_n() exclude points on the
arm one past what was requested
- new CellularRule57
Version 66, February 2012
- new TerdragonMidpoint
- DragonCurve,DragonMidpoint,DragonRounded,TerdragonCurve faster xy_to_n()
Version 65, January 2012
- new parameter_info_hash(), n_frac_discontinuity()
Version 64, January 2012
- new AnvilSpiral, AlternatePaper, ComplexPlus, TerdragonCurve
Version 63, January 2012
- new class_x_negative() and class_y_negative() methods
- new CellularRule, ComplexRevolving, Math::NumSeq::PlanePathN
- Math::NumSeq::PlanePathCoord etc new planepath_object option
Version 62, December 2011
- new FractionsTree
Version 61, December 2011
- new FactorRationals
Version 60, December 2011
- new GcdRationals
Version 59, December 2011
- new AR2W2Curve
Version 58, December 2011
- new DiagonalRationals, StaircaseAlternating,
Math::NumSeq::PlanePathDelta
Version 57, December 2011
- new HilbertSpiral
- LTiling new L_fill "left" and "upper"
Version 56, December 2011
- new CincoCurve, DiagonalsAlternating, LTiling
Version 55, November 2011
- new KochelCurve, MPeaks
- Flowsnake,QuintetCurve faster xy_to_n()
Version 54, November 2011
- new WunderlichMeander
- PlanePathCoord new coordinate_type "Product","DiffXY","DiffYX","AbsDiff"
- BetaOmega,CellularRule190 exact rect_to_n_range()
Version 53, November 2011
- new FibonacciWordFractal, Math::NumSeq::PlanePathCoord
Version 52, November 2011
- new BetaOmega, CornerReplicate, DigitGroups, HIndexing
Version 51, October 2011
- new CellularRule190
Version 50, October 2011
- DragonRounded fix xy_to_n() with arms=2,3,4 on innermost XY=0,1
- SierpinskiCurve fixes for rect_to_n_range()
Version 49, October 2011
- new AztecDiamondRings, DivisibleColumns, SierpinskiCurve,
UlamWarburtonQuarter
- SierpinskiArrowheadCentres fix for n_to_xy() on fractional $n
Version 48, October 2011
- new UlamWarburton
Version 47, October 2011
- new SquareReplicate
Version 46, September 2011
- new GosperReplicate
Version 45, September 2011
- new QuintetCurve, QuintetCentres, QuintetReplicate
Version 44, September 2011
- new ComplexMinus
- RationalsTree new tree_type=Drib
- Corner new wider parameter
Version 43, September 2011
- new KochSquareflakes, RationalsTree
- new parameter_info_array(), parameter_info_list()
Version 42, September 2011
- new SierpinskiArrowheadCentres, SierpinskiTriangle
Version 41, August 2011
- new QuadricCurve, QuadricIslands, ImaginaryBase
Version 40, August 2011
- new DragonRounded, CellularRule54
- new arms_count() method
- Flowsnake, FlowsnakeCentres new "arms" parameter
Version 39, August 2011
- new DragonCurve, DragonMidpoint
Version 38, August 2011
- new Flowsnake, FlowsnakeCentres
Version 37, July 2011
- new SquareArms, DiamondArms, File
Version 36, July 2011
- new HexArms
- PeanoCurve new radix parameter
Version 35, July 2011
- new GosperSide
- fixes for experimental BigFloat support
Version 34, July 2011
- ZOrderCurve new radix parameter
Version 33, July 2011
- new GosperIslands
Version 32, June 2011
- new SierpinskiArrowhead, CoprimeColumns
Version 31, June 2011
- KochCurve fix for fractional N
Version 31, June 2011
- PythagoreanTree avoid dubious hypot() on darwin 8.11.0
Version 30, May 2011
- new TriangularHypot, KochCurve, KochPeaks, KochSnowflakes
Version 29, May 2011
- GreekKeySpiral rect_to_n_range() tighter $n_lo
- tests more diagnostics on PythagoreanTree
Version 28, May 2011
- PixelRings xy_to_n() fix some X==Y points should be undef
Version 27, May 2011
- new GreekKeySpiral
Version 26, May 2011
- new PythagoreanTree
- Rows,Columns more care against width<=0 or height<=0
Version 25, May 2011
- tests fix neg zero for long double NV
Version 24, May 2011
- tests fix OEIS file comparisons
- MultipleRings xy_to_n() fix for x=-0,y=0
Version 23, April 2011
- new ArchimedeanChords
- TheodorusSpiral rect_to_n_range() tighter $n_lo
Version 22, March 2011
- new n_start() method
- SacksSpiral rect_to_n_range() include N=0
Version 21, February 2011
- new Hypot, HypotOctant, OctagramSpiral
- TheodorusSpiral, VogelFloret allow for xy_to_n() result bigger than IV
(though that big is probably extremely slow)
Version 20, February 2011
- fix Makefile.PL for perl 5.6.0
- tests avoid stringized "-0" from perl 5.6.x
Version 19, January 2011
- new PixelRings
Version 18, January 2011
- avoid some 5.12 warnings on infs
Version 17, January 2011
- avoid some inf loops and div by zeros for n=infinity or x,y=infinity
(handling of infinity is unspecified, but at least don't hang)
- PyramidRows, PyramidSides exact rect_to_n_range()
Version 16, January 2011
- new PeanoCurve, Staircase
Version 15, January 2011
- MultipleRings fix xy_to_n() and rect_to_n_range() at 0,0
- Corners,Diagonals,MultipleRings tighter rect_to_n_range()
Version 14, December 2010
- HilbertCurve exact rect_to_n_range()
Version 13, December 2010
- new HilbertCurve, ZOrderCurve
Version 12, October 2010
- oops, VogelFloret botched rect_to_n_range()
Version 11, October 2010
- VogelFloret new rotation and radius parameters
- SacksSpiral,VogelFloret tighter rect_to_n_range() when away from origin
Version 10, October 2010
- fix MultipleRings xy_to_n()
Version 9, September 2010
- HexSpiral and HexSpiralSkewed new "wider" parameter
Version 8, September 2010
- tests fix stray 5.010 should be just 5.004
Version 7, August 2010
- new MultipleRings
- VogelFloret xy_to_n() fix for positions away from exact N
- Rows, Columns rect_to_n_range() tighter
Version 6, August 2010
- new TheodorusSpiral
Version 5, July 2010
- SquareSpiral new "wider" parameter
Version 4, July 2010
- new PentSpiral, HeptSpiralSkewed
- PyramidRows "step" parameter
Version 3, July 2010
- new PyramidSpiral, TriangleSpiral, TriangleSpiralSkewed, PentSpiralSkewed
Version 2, July 2010
- in Diagonals don't negative sqrt() if n=0
Version 1, July 2010
- the first version
Math-PlanePath-113/xtools/ 0002755 0001750 0001750 00000000000 12255673733 013246 5 ustar gg gg Math-PlanePath-113/xtools/my-wunused.sh 0000755 0001750 0001750 00000002741 12072627526 015720 0 ustar gg gg #!/bin/sh
# my-wunused.sh -- run warnings::unused on dist files
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# my-wunused.sh is shared by several distributions.
#
# my-wunused.sh 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, or (at your option) any later
# version.
#
# my-wunused.sh 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 file. If not, see .
set -e
set -x
EXE_FILES=`sed -n 's/^EXE_FILES = \(.*\)/\1/p' Makefile`
TO_INST_PM=`find lib -name \*.pm`
LINT_FILES="Makefile.PL $EXE_FILES $TO_INST_PM"
if test -e "t/*.t"; then
LINT_FILES="$LINT_FILES t/*.t"
fi
if test -e "xt/*.t"; then
LINT_FILES="$LINT_FILES xt/*.t"
fi
for i in t xt examples devel; do
if test -e "$i/*.pl"; then
LINT_FILES="$LINT_FILES $i/*.pl"
fi
if test -e "$i/*.pm"; then
LINT_FILES="$LINT_FILES $i/*.pm"
fi
done
echo "$LINT_FILES"
for i in $LINT_FILES; do
# warnings::unused broken by perl 5.14, so use 5.10 for checks
# perl-5.10.0 -I /usr/share/perl5 -Mwarnings::unused=-global -I lib -c $i
perl -MTest::Vars -e 'Test::Vars::vars_ok($ARGV[0])' "$i"
done
Math-PlanePath-113/xtools/my-diff-prev.sh 0000755 0001750 0001750 00000003006 11776230514 016100 0 ustar gg gg #!/bin/sh
# my-diff-prev.sh -- diff against previous version
# Copyright 2009, 2010, 2011, 2012 Kevin Ryde
# my-diff-prev.sh is shared by several distributions.
#
# my-diff-prev.sh 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, or (at your option) any later
# version.
#
# my-diff-prev.sh 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 file. If not, see .
set -e
set -x
DISTNAME=`sed -n 's/^DISTNAME = \(.*\)/\1/p' Makefile`
if test -z "$DISTNAME"; then
echo "DISTNAME not found"
exit 1
fi
VERSION=`sed -n 's/^VERSION = \(.*\)/\1/p' Makefile`
if test -z "$VERSION"; then
echo "VERSION not found"
exit 1
fi
case $VERSION in
3.*) PREV_VERSION=3.018000 ;;
1.*) PREV_VERSION=1.16 ;;
*) PREV_VERSION="`expr $VERSION - 1`" ;;
esac
if test -z "$VERSION"; then
echo "PREV_VERSION not established"
exit 1
fi
rm -rf diff.tmp
mkdir -p diff.tmp
(cd diff.tmp;
tar xfz ../$DISTNAME-$PREV_VERSION.tar.gz
tar xfz ../$DISTNAME-$VERSION.tar.gz
diff -ur $DISTNAME-$PREV_VERSION \
$DISTNAME-$VERSION \
>tree.diff || true
)
${PAGER:-more} diff.tmp/tree.diff || true
rm -rf diff.tmp
exit 0
Math-PlanePath-113/xtools/my-tags.sh 0000644 0001750 0001750 00000002003 11714065142 015140 0 ustar gg gg #!/bin/sh
# my-tags.sh -- make tags
# Copyright 2009, 2010, 2011, 2012 Kevin Ryde
# my-tags.sh is shared by several distributions.
#
# my-tags.sh 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, or (at your option) any later
# version.
#
# my-tags.sh 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 file. If not, see .
set -e
set -x
# in a hash-style multi-const this "use constant" pattern only picks up the
# first constant, unfortunately, but it's better than nothing
etags \
--regex='{perl}/use[ \t]+constant\(::defer\)?[ \t]+\({[ \t]*\)?\([A-Za-z_][^ \t=,;]+\)/\3/' \
`find lib -type f`
Math-PlanePath-113/xtools/my-check-spelling.sh 0000755 0001750 0001750 00000003160 12252141675 017106 0 ustar gg gg #!/bin/sh
# my-check-spelling.sh -- grep for spelling errors
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# my-check-spelling.sh is shared by several distributions.
#
# my-check-spelling.sh 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, or (at your option) any later
# version.
#
# my-check-spelling.sh 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 file. If not, see .
set -e
# set -x
# | tee /dev/stdout
# -name samp -prune \
# -o -name formats -prune \
# -o -name "*~" -prune \
# -o -name "*.tar.gz" -prune \
# -o -name "*.deb" -prune \
# -o
# -o -name dist-deb -prune \
# | egrep -v '(Makefile|dist-deb)' \
if find . -name my-check-spelling.sh -prune \
-o -type f -print0 \
| xargs -0 egrep --color=always -nHi 'optino|recurrance|nineth|\bon on\b|\bto to\b|tranpose|adjustement|glpyh|rectanglar|availabe|grabing|cusor|refering|writeable|nineth|\bommitt?ed|omited|[$][rd]elf|requrie|noticable|continous|existant|explict|agument|destionation|\bthe the\b|\bfor for\b|\bare have\b|\bare are\b|\bwith with\b|\bin in\b|\b[tw]hen then\b|\bnote sure\b|\bnote yet\b|correspondance|sprial|wholely|satisif'
then
# nothing found
exit 1
else
exit 0
fi
Math-PlanePath-113/xtools/my-kwalitee.sh 0000755 0001750 0001750 00000002146 11775434756 016044 0 ustar gg gg #!/bin/sh
# my-kwalitee.sh -- run cpants_lint kwalitee checker
# Copyright 2009, 2010, 2011, 2012 Kevin Ryde
# my-kwalitee.sh is shared by several distributions.
#
# my-kwalitee.sh 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, or (at your option) any later
# version.
#
# my-kwalitee.sh 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 file. If not, see .
# Module::CPANTS::Analyse
set -e
set -x
DISTVNAME=`sed -n 's/^DISTVNAME = \(.*\)/\1/p' Makefile`
if test -z "$DISTVNAME"; then
echo "DISTVNAME not found"
exit 1
fi
if [ -e ~/bin/my-gpg-agent-daemon ]; then
eval `my-gpg-agent-daemon`
echo "gpg-agent $GPG_AGENT_INFO"
fi
TGZ="$DISTVNAME.tar.gz"
make "$TGZ"
cpants_lint "$TGZ"
Math-PlanePath-113/xtools/my-pc.sh 0000755 0001750 0001750 00000003233 12206324154 014613 0 ustar gg gg #!/bin/sh
# my-pc.sh -- run cpants_lint kwalitee checker
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# my-pc.sh is shared by several distributions.
#
# my-pc.sh 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, or (at your
# option) any later version.
#
# my-pc.sh 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 file. If not, see .
set -x
# PERLRUNINST=`sed -n 's/^PERLRUNINST = \(.*\)/\1/p' Makefile`
# if test -z "$PERLRUNINST"; then
# echo "PERLRUNINST not found"
# exit 1
# fi
EXE_FILES=`sed -n 's/^EXE_FILES = \(.*\)/\1/p' Makefile`
TO_INST_PM=`find lib -name \*.pm`
LINT_FILES="Makefile.PL $EXE_FILES $TO_INST_PM"
if test -e "t/*.t"; then
LINT_FILES="$LINT_FILES t/*.t"
fi
if test -e "xt/*.t"; then
LINT_FILES="$LINT_FILES xt/*.t"
fi
for i in t xt examples devel; do
if test -e "$i/*.pl"; then
LINT_FILES="$LINT_FILES $i/*.pl"
fi
if test -e "$i/*.pm"; then
LINT_FILES="$LINT_FILES $i/*.pm"
fi
done
perl -e 'use Test::Vars; all_vars_ok()'
# MyMakeMakerExtras_Pod_Coverage
perl -e 'use Pod::Coverage package => $class'
podlinkcheck -I lib `ls $LINT_FILES | grep -v '\.bash$$|\.desktop$$\.png$$|\.xpm$$'`
podchecker -nowarnings `ls $LINT_FILES | grep -v '\.bash$$|\.desktop$$\.png$$|\.xpm$$'`
perlcritic $LINT_FILES
Math-PlanePath-113/xtools/my-deb.sh 0000755 0001750 0001750 00000006761 12070737741 014765 0 ustar gg gg #!/bin/sh
# my-deb.sh -- make .deb
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# my-deb.sh is shared by several distributions.
#
# my-deb.sh 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, or (at your option) any later
# version.
#
# my-deb.sh 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 file. If not, see .
# warnings::unused broken by perl 5.14, so use 5.10 for checks
set -e
set -x
DISTNAME=`sed -n 's/^DISTNAME = \(.*\)/\1/p' Makefile`
if test -z "$DISTNAME"; then
echo "DISTNAME not found"
exit 1
fi
DISTVNAME=`sed -n 's/^DISTVNAME = \(.*\)/\1/p' Makefile`
if test -z "$DISTVNAME"; then
echo "DISTVNAME not found"
exit 1
fi
VERSION=`sed -n 's/^VERSION = \(.*\)/\1/p' Makefile`
if test -z "$VERSION"; then
echo "VERSION not found"
exit 1
fi
XS_FILES=`sed -n 's/^XS_FILES = \(.*\)/\1/p' Makefile`
EXE_FILES=`sed -n 's/^EXE_FILES = \(.*\)/\1/p' Makefile`
if test -z "$XS_FILES"
then DPKG_ARCH=all
else DPKG_ARCH=`dpkg --print-architecture`
fi
# programs named after the dist, libraries named with "lib"
# gtk2-ex-splash and wx-perl-podbrowser programs are lib too though
DEBNAME=`echo $DISTNAME | tr A-Z a-z`
case "$EXE_FILES" in
gtk2-ex-splash|wx-perl-podbrowser|'')
DEBNAME="lib${DEBNAME}-perl" ;;
esac
DEBVNAME="${DEBNAME}_$VERSION-0.1"
DEBFILE="${DEBVNAME}_$DPKG_ARCH.deb"
# ExtUtils::MakeMaker 6.42 of perl 5.10.0 makes "$(DISTVNAME).tar.gz" depend
# on "$(DISTVNAME)" distdir directory, which is always non-existent after a
# successful dist build, so the .tar.gz is always rebuilt.
#
# So although the .deb depends on the .tar.gz don't express that here or it
# rebuilds the .tar.gz every time.
#
# The right rule for the .tar.gz would be to depend on the files which go
# into it of course ...
#
# DISPLAY is unset for making a deb since under fakeroot gtk stuff may try
# to read config files like ~/.pangorc from root's home dir /root/.pangorc,
# and that dir will be unreadable by ordinary users (normally), provoking
# warnings and possible failures from nowarnings().
#
test -f $DISTVNAME.tar.gz || make $DISTVNAME.tar.gz
debver="`dpkg-parsechangelog -c1 | sed -n -r -e 's/^Version: (.*)-[0-9.]+$/\1/p'`"
echo "debver $debver", want $VERSION
test "$debver" = "$VERSION"
rm -rf $DISTVNAME
tar xfz $DISTVNAME.tar.gz
unset DISPLAY; export DISPLAY
cd $DISTVNAME
dpkg-checkbuilddeps debian/control
fakeroot debian/rules binary
cd ..
rm -rf $DISTVNAME
#------------------------------------------------------------------------------
# lintian .deb and source
lintian -I -i \
--suppress-tags new-package-should-close-itp-bug,desktop-entry-contains-encoding-key \
$DEBFILE
TEMP="/tmp/temp-lintian-$DISTVNAME"
rm -rf $TEMP
mkdir $TEMP
cp $DISTVNAME.tar.gz $TEMP/${DEBNAME}_$VERSION.orig.tar.gz
cd $TEMP
tar xfz ${DEBNAME}_$VERSION.orig.tar.gz
if test "$DISTVNAME" != "$DEBNAME-$VERSION"; then
mv -T $DISTVNAME $DEBNAME-$VERSION
fi
dpkg-source -b $DEBNAME-$VERSION \
${DEBNAME}_$VERSION.orig.tar.gz; \
lintian -I -i \
--suppress-tags maintainer-upload-has-incorrect-version-number,empty-debian-diff,debian-rules-uses-deprecated-makefile *.dsc
cd /
rm -rf $TEMP
exit 0
Math-PlanePath-113/xtools/my-manifest.sh 0000755 0001750 0001750 00000001652 11764227757 016045 0 ustar gg gg #!/bin/sh
# my-manifest.sh -- update MANIFEST file
# Copyright 2009, 2010, 2011, 2012 Kevin Ryde
# my-manifest.sh is shared by several distributions.
#
# my-manifest.sh 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, or (at your option) any later
# version.
#
# my-manifest.sh 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 file. If not, see .
set -e
if [ -e MANIFEST ]; then
mv MANIFEST MANIFEST.old || true
fi
touch SIGNATURE
(
make manifest 2>&1;
diff -u MANIFEST.old MANIFEST
) | ${PAGER:-more}
Math-PlanePath-113/xtools/my-check-copyright-years.sh 0000755 0001750 0001750 00000004037 12230015164 020413 0 ustar gg gg #!/bin/sh
# my-check-copyright-years.sh -- check copyright years in dist
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# my-check-copyright-years.sh is shared by several distributions.
#
# my-check-copyright-years.sh 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, or (at your
# option) any later version.
#
# my-check-copyright-years.sh 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 file. If not, see .
set -e
#set -x
# find files in the dist with mod times this year, but without this year in
# the copyright line
if test -z "$DISTVNAME"; then
DISTVNAME=`sed -n 's/^DISTVNAME = \(.*\)/\1/p' Makefile`
fi
if test -z "$DISTVNAME"; then
echo "DISTVNAME not found"
exit 1
fi
MY_HIDE=
year=`date +%Y`
result=0
# files with dates $year
tar tvfz $DISTVNAME.tar.gz \
| egrep "$year-|debian/copyright" \
| sed "s:^.*$DISTVNAME/::" \
| {
while read i
do
# echo "consider $i"
GREP=grep
case $i in \
'' | */ \
| ppport.h \
| debian/changelog | debian/compat | debian/doc-base \
| debian/patches/*.diff | debian/source/format \
| COPYING | MANIFEST* | SIGNATURE | META.yml | META.json \
| version.texi | */version.texi \
| *utf16* | examples/rs''s2lea''fnode.conf \
| */MathI''mage/ln2.gz | */MathI''mage/pi.gz \
| *.mo | *.locatedb* | t/samp.* \
| t/empty.dat | t/*.xpm | t/*.xbm | t/*.jpg | t/*.gif \
| t/*.g${MY_HIDE}d)
continue ;;
*.gz)
GREP=zgrep
esac; \
if test -e "$srcdir/$i"
then f="$srcdir/$i"
else f="$i"
fi
if $GREP -q -e "Copyright.*$year" $f
then :;
else
echo "$i:1: this file"
grep Copyright $f
result=1
fi
done
}
exit $result
Math-PlanePath-113/xt/ 0002755 0001750 0001750 00000000000 12255673733 012351 5 ustar gg gg Math-PlanePath-113/xt/0-Test-ConsistentVersion.t 0000644 0001750 0001750 00000002253 11655356324 017304 0 ustar gg gg #!/usr/bin/perl -w
# 0-Test-ConsistentVersion.t -- run Test::ConsistentVersion if available
# Copyright 2011 Kevin Ryde
# 0-Test-ConsistentVersion.t is shared by several distributions.
#
# 0-Test-ConsistentVersion.t 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, or (at your option) any
# later version.
#
# 0-Test-ConsistentVersion.t 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 file. If not, see .
use 5.004;
use strict;
use Test::More;
eval { require Test::ConsistentVersion }
or plan skip_all => "due to Test::ConsistentVersion not available -- $@";
Test::ConsistentVersion::check_consistent_versions
(no_readme => 1, # no version number in my READMEs
no_pod => 1, # no version number in my docs, at the moment
);
# ! -e 'README');
exit 0;
Math-PlanePath-113/xt/0-Test-Synopsis.t 0000755 0001750 0001750 00000001764 11655356314 015444 0 ustar gg gg #!/usr/bin/perl -w
# 0-Test-Synopsis.t -- run Test::Synopsis if available
# Copyright 2009, 2010, 2011 Kevin Ryde
# 0-Test-Synopsis.t is shared by several distributions.
#
# 0-Test-Synopsis.t 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, or (at your option) any later
# version.
#
# 0-Test-Synopsis.t 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 file. If not, see .
use 5.004;
use strict;
use Test::More;
eval 'use Test::Synopsis; 1'
or plan skip_all => "due to Test::Synopsis not available -- $@";
## no critic (ProhibitCallsToUndeclaredSubs)
all_synopsis_ok();
exit 0;
Math-PlanePath-113/xt/oeis-duplicate.t 0000644 0001750 0001750 00000003171 12136177165 015441 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Check that OEIS A-number sequences implemented by PlanePath modules aren't
# already supplied by the core NumSeq.
#
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Devel::Comments '###';
use Math::NumSeq::OEIS::Catalogue::Plugin::BuiltinTable;
use Math::NumSeq::OEIS::Catalogue::Plugin::PlanePath;
my %builtin_anums;
foreach my $info (@{Math::NumSeq::OEIS::Catalogue::Plugin::BuiltinTable::info_arrayref()}) {
$builtin_anums{$info->{'anum'}} = $info;
}
my $good = 1;
my $count = 0;
foreach my $info (@{Math::NumSeq::OEIS::Catalogue::Plugin::PlanePath::info_arrayref()}) {
my $anum = $info->{'anum'};
if ($builtin_anums{$anum}) {
MyTestHelpers::diag ("$anum already a NumSeq builtin");
$good = 0;
}
$count++;
}
ok ($good);
MyTestHelpers::diag ("total $count PlanePath A-numbers");
exit 0;
Math-PlanePath-113/xt/0-no-debug-left-on.t 0000755 0001750 0001750 00000006515 12044143060 015722 0 ustar gg gg #!/usr/bin/perl -w
# 0-no-debug-left-on.t -- check no Smart::Comments left on
# Copyright 2011, 2012 Kevin Ryde
# 0-no-debug-left-on.t is shared by several distributions.
#
# 0-no-debug-left-on.t 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, or (at your option) any
# later version.
#
# 0-no-debug-left-on.t 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 file. If not, see .
# cf Test::NoSmartComments which uses Module::ScanDeps.
require 5;
use strict;
Test::NoDebugLeftOn->Test_More(verbose => 0);
exit 0;
package Test::NoDebugLeftOn;
use strict;
use ExtUtils::Manifest;
sub Test_More {
my ($class, %options) = @_;
require Test::More;
Test::More::plan (tests => 1);
Test::More::ok ($class->check (diag => \&Test::More::diag,
%options));
1;
}
sub check {
my ($class, %options) = @_;
my $diag = $options{'diag'};
if (! -e 'Makefile.PL') {
&$diag ('skip, no Makefile.PL so not ExtUtils::MakeMaker');
return 1;
}
my $href = ExtUtils::Manifest::maniread();
my @files = keys %$href;
my $good = 1;
my @perl_files = grep {m{
^lib/
|^(lib|examples|x?t)/.*\.(p[lm]|t)$
|^Makefile.PL$
|^[^/]+$
}x
} @files;
my $filename;
foreach $filename (@perl_files) {
if ($options{'verbose'}) {
&$diag ("perl file ",$filename);
}
if (! open FH, "< $filename") {
&$diag ("Oops, cannot open $filename: $!");
$good = 0;
next;
}
while () {
if (/^__END__/) {
last;
}
# only a DEBUG=> non-zero number is bad, so an expression can copy a
# debug from another package
if (/(DEBUG\s*=>\s*[1-9][0-9]*)/
|| /^[ \t]*((use|no) (Smart|Devel)::Comments)/
|| /^[ \t]*(use lib\b.*devel.*)/
) {
print STDERR "\n$filename:$.: leftover: $_\n";
$good = 0;
}
}
if (! close FH) {
&$diag ("Oops, error closing $filename: $!");
$good = 0;
next;
}
}
my @C_files = grep {m{
# toplevel or lib .c and .xs files
^[^/]*\.([ch]|xs)$
|^(lib|examples|x?t)/.*\.([ch]|xs)$
}x
} @files;
foreach $filename (@C_files) {
if ($options{'verbose'}) {
&$diag ("C/XS file ",$filename);
}
if (! open FH, "< $filename") {
&$diag ("Oops, cannot open $filename: $!");
$good = 0;
next;
}
while () {
if (/^#\s*define\s+DEBUG\s+[1-9]/
) {
print STDERR "\n$filename:$.: leftover: $_\n";
$good = 0;
}
}
if (! close FH) {
&$diag ("Oops, error closing $filename: $!");
$good = 0;
next;
}
}
&$diag ("checked ",scalar(@perl_files)," perl files, ",
scalar(@C_files)," C/XS files\n");
return $good;
}
Math-PlanePath-113/xt/bigrat.t 0000644 0001750 0001750 00000052747 12165210607 014006 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Crib notes:
#
# In perl 5.8.4 "BigInt != BigRat" doesn't work, must have it other way
# around as "BigRat != BigInt". Symptom is "uninitialized" warnings.
#
use 5.004;
use strict;
use Test;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $test_count = (tests => 468)[1];
plan tests => $test_count;
if (! eval { require Math::BigRat; 1 }) {
MyTestHelpers::diag ('skip due to Math::BigRat not available -- ',$@);
foreach (1 .. $test_count) {
skip ('due to no Math::BigRat', 1, 1);
}
exit 0;
}
MyTestHelpers::diag ('Math::BigRat version ', Math::BigRat->VERSION);
if (! Math::BigRat->can('as_float')) {
MyTestHelpers::diag ('skip due to Math::BigRat->as_float method not available');
foreach (1 .. $test_count) {
skip ('due to no as_float()', 1, 1);
}
exit 0;
}
{
my $f = Math::BigRat->new('-1/2');
my $int = int($f);
if ($int == 0) {
MyTestHelpers::diag ('BigRat int(-1/2)==0, good');
} else {
MyTestHelpers::diag ("BigRat has int(-1/2) != 0 dodginess: value is '$int'");
}
}
require Math::BigInt;
MyTestHelpers::diag ('Math::BigInt version ', Math::BigInt->VERSION);
{
my $n = Math::BigInt->new(2) ** 256;
my $int = int($n);
if (! ref $int) {
MyTestHelpers::diag ('skip due to Math::BigInt no "int" operator');
foreach (1 .. $test_count) {
skip ('due to no Math::BigInt int() operator', 1, 1);
}
exit 0;
}
}
# doesn't help sqrt(), slows down blog()
#
# require Math::BigFloat;
# Math::BigFloat->precision(-2000); # digits right of decimal point
#------------------------------------------------------------------------------
# round_nearest()
use Math::PlanePath::Base::Generic
'round_nearest';
ok (round_nearest(Math::BigRat->new('-7/4')) == -2, 1);
ok (round_nearest(Math::BigRat->new('-3/2')) == -1, 1);
ok (round_nearest(Math::BigRat->new('-5/4')) == -1, 1);
ok (round_nearest(Math::BigRat->new('-3/4')) == -1, 1);
ok (round_nearest(Math::BigRat->new('-1/2')) == 0, 1);
ok (round_nearest(Math::BigRat->new('-1/4')) == 0, 1);
ok (round_nearest(Math::BigRat->new('1/4')) == 0, 1);
ok (round_nearest(Math::BigRat->new('5/4')) == 1, 1);
ok (round_nearest(Math::BigRat->new('3/2')) == 2, 1);
ok (round_nearest(Math::BigRat->new('7/4')) == 2, 1);
ok (round_nearest(Math::BigRat->new('2')) == 2, 1);
#------------------------------------------------------------------------------
# floor()
use Math::PlanePath::Base::Generic
'floor';
ok (floor(Math::BigRat->new('-7/4')) == -2, 1);
ok (floor(Math::BigRat->new('-3/2')) == -2, 1);
ok (floor(Math::BigRat->new('-5/4')) == -2, 1);
ok (floor(Math::BigRat->new('-3/4')) == -1, 1);
ok (floor(Math::BigRat->new('-1/2')) == -1, 1);
ok (floor(Math::BigRat->new('-1/4')) == -1, 1);
ok (floor(Math::BigRat->new('1/4')) == 0, 1);
ok (floor(Math::BigRat->new('3/4')) == 0, 1);
ok (floor(Math::BigRat->new('5/4')) == 1, 1);
ok (floor(Math::BigRat->new('3/2')) == 1, 1);
ok (floor(Math::BigRat->new('7/4')) == 1, 1);
ok (floor(Math::BigRat->new('2')) == 2, 1);
#------------------------------------------------------------------------------
# MultipleRings
{
require Math::PlanePath::MultipleRings;
my $width = 5;
my $path = Math::PlanePath::MultipleRings->new (step => 6);
{
my $n = Math::BigRat->new(23);
my ($got_x,$got_y) = $path->n_to_xy($n);
ok (!! (ref $got_x && $got_x->isa('Math::BigFloat')), 1);
ok ($got_x > 0 && $got_x < 1,
1,
"MultipleRings n_to_xy($n) got_x $got_x");
ok ($got_y > 2.5 && $got_y < 3.1,
1,
"MultipleRings n_to_xy($n) got_y $got_y");
}
}
#------------------------------------------------------------------------------
# CoprimeColumns
{
require Math::PlanePath::CoprimeColumns;
my $path = Math::PlanePath::CoprimeColumns->new;
{
my $n = Math::BigRat->new('-2/3');
my @ret = $path->n_to_xy($n);
ok (scalar(@ret), 0);
}
{
my $n = Math::BigRat->new(0);
my $want_x = 1;
my $want_y = 1;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $want_x, 1, "got $got_x want $want_x");
ok ($got_y == $want_y);
my $got_n = $path->xy_to_n($want_x,$want_y);
ok ($got_n == 0, 1);
}
# pending int(-1/2)==0 dodginess
# {
# my $n = Math::BigRat->new('-1/3');
# my $want_x = 1;
# my $want_y = Math::BigRat->new('1/3');
#
# my ($got_x,$got_y) = $path->n_to_xy($n);
# ok ($got_x == $want_x, 1, "got $got_x want $want_x");
# ok ($got_y == $want_y);
#
# my $got_n = $path->xy_to_n($want_x,$want_y);
# ok ($got_n == 0, 1);
# }
{
my $n = Math::BigRat->new('1/2');
my $want_x = 2;
my $want_y = Math::BigRat->new('1/2');
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $want_x, 1, "got $got_x want $want_x");
ok ($got_y == $want_y);
my $got_n = $path->xy_to_n($want_x,$want_y);
ok ($got_n == 1, 1);
}
}
#------------------------------------------------------------------------------
# DiagonalRationals
{
require Math::PlanePath::DiagonalRationals;
my $path = Math::PlanePath::DiagonalRationals->new;
{
my $n = Math::BigRat->new('1/3');
my @ret = $path->n_to_xy($n);
ok (scalar(@ret), 0);
}
{
my $n = Math::BigRat->new('1/2');
my $want_x = Math::BigRat->new('1/2');
my $want_y = Math::BigRat->new('3/2');
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $want_x, 1,
"DiagonalRationals n_to_xy() from 4/3, X got $got_x want $want_x");
ok ($got_y == $want_y, 1,
"DiagonalRationals n_to_xy() from 4/3, Y got $got_y want $want_y");
my $got_n = $path->xy_to_n($want_x,$want_y);
ok ($got_n == 1, 1, 'DiagonalRationals xy_to_n($want_x,$want_y) from 1/2');
}
{
my $n = Math::BigRat->new('4/3');
my $want_x = Math::BigRat->new('4/3');
my $want_y = Math::BigRat->new('2/3');
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $want_x, 1,
"DiagonalRationals n_to_xy() from 4/3, X got $got_x want $want_x");
ok ($got_y == $want_y, 1,
"DiagonalRationals n_to_xy() from 4/3, Y got $got_y want $want_y");
my $got_n = $path->xy_to_n($want_x,$want_y);
ok ($got_n == 1, 1, 'DiagonalRationals xy_to_n($want_x,$want_y) from 4/3');
}
}
#------------------------------------------------------------------------------
# Rows
{
require Math::PlanePath::Rows;
my $width = 5;
my $path = Math::PlanePath::Rows->new (width => $width);
{
my $y = Math::BigRat->new(2) ** 128;
my $x = 4;
my $n = $y*$width + $x + 1;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $x, 1, "got $got_x want $x");
ok ($got_y == $y);
my $got_n = $path->xy_to_n($x,$y);
ok ($got_n == $n, 1);
}
{
my $n = Math::BigRat->new('4/3');
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ("$got_x", '1/3');
ok ($got_y == 0, 1);
}
{
my $n = Math::BigRat->new('4/3') + 15;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ("$got_x", '1/3');
ok ($got_y == 3, 1);
}
{
my $n = Math::BigRat->new('4/3') - 15;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ("$got_x", '1/3');
ok ($got_y == -3, 1);
}
}
#------------------------------------------------------------------------------
# Diagonals
{
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::Diagonals->new;
{
my $x = Math::BigRat->new(2) ** 128 - 1;
my $n = ($x+1)*($x+2)/2; # triangular numbers on Y=0 horizontal
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $x, 1, "got x=$got_x want $x");
ok ($got_y == 0, 1, "got y=$got_y want 0");
my $got_n = $path->xy_to_n($x,0);
ok ($got_n == $n, 1);
}
{
my $x = Math::BigRat->new(2) ** 128 - 1;
my $n = ($x+1)*($x+2)/2; # Y=0 horizontal
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == $x, 1);
ok ($got_y == 0, 1);
my $got_n = $path->xy_to_n($x,0);
ok ($got_n == $n, 1);
}
{
my $y = Math::BigRat->new(2) ** 128 - 1;
my $n = $y*($y+1)/2 + 1; # X=0 vertical
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x == 0, 1);
ok ($got_y == $y, 1);
my $got_n = $path->xy_to_n(0,$y);
ok ($got_n, $n);
}
{
my $n = Math::BigRat->new(-1);
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x, undef);
ok ($got_y, undef);
}
{
my $n = Math::BigRat->new(0.5);
my ($got_x,$got_y) = $path->n_to_xy($n);
ok (!! $got_x->isa('Math::BigRat'), 1);
ok (!! $got_y->isa('Math::BigRat'), 1);
ok ($got_x == -0.5, 1);
ok ($got_y == 0.5, 1);
}
}
#------------------------------------------------------------------------------
# PeanoCurve
require Math::PlanePath::PeanoCurve;
{
my $path = Math::PlanePath::PeanoCurve->new;
require Math::BigRat;
my $n = Math::BigRat->new(9) ** 128 + Math::BigRat->new('4/3');
my $want_x = Math::BigRat->new(3) ** 128 + Math::BigRat->new('4/3');
my $want_y = Math::BigRat->new(3) ** 128 - 1;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x, $want_x);
ok ($got_y, $want_y);
}
#------------------------------------------------------------------------------
# ZOrderCurve
require Math::PlanePath::ZOrderCurve;
{
my $path = Math::PlanePath::ZOrderCurve->new;
require Math::BigRat;
my $n = Math::BigRat->new(4) ** 128 + Math::BigRat->new('1/3');
$n->isa('Math::BigRat') || die "Oops, n not a BigRat";
my $want_x = Math::BigRat->new(2) ** 128 + Math::BigRat->new('1/3');
my $want_y = 0;
my ($got_x,$got_y) = $path->n_to_xy($n);
ok ($got_x, $want_x);
ok ($got_y, $want_y);
}
#------------------------------------------------------------------------------
# round_down_pow()
use Math::PlanePath::Base::Digits 'round_down_pow';
{
my $orig = Math::BigRat->new(3) ** 128 + Math::BigRat->new('1/7');
my $n = Math::BigRat->new(3) ** 128 + Math::BigRat->new('1/7');
my ($pow,$exp) = round_down_pow($n,3);
ok ($n, $orig);
ok ($pow, Math::BigRat->new(3) ** 128);
ok ($exp, 128);
}
{
my $orig = Math::BigRat->new(3) ** 128;
my $n = Math::BigRat->new(3) ** 128;
my ($pow,$exp) = round_down_pow($n,3);
ok ($n, $orig);
ok ($pow, Math::BigRat->new(3) ** 128);
ok ($exp, 128);
}
#------------------------------------------------------------------------------
my @modules = (
'AztecDiamondRings', # but not across ring end
'PyramidSpiral',
'CfracDigits,radix=1',
'CfracDigits',
'CfracDigits,radix=3',
'CfracDigits,radix=4',
'CfracDigits,radix=10',
'CfracDigits,radix=37',
'ChanTree',
'ChanTree,k=2',
'ChanTree,k=4',
'ChanTree,k=5',
'ChanTree,k=7',
'ChanTree,reduced=1',
'ChanTree,reduced=1,k=2',
'ChanTree,reduced=1,k=4',
'ChanTree,reduced=1,k=5',
'ChanTree,reduced=1,k=7',
'RationalsTree',
'RationalsTree,tree_type=L',
'RationalsTree,tree_type=HCS',
'FractionsTree',
'DekkingCurve',
'DekkingCentres',
'QuintetCurve',
'QuintetCurve,arms=2',
'QuintetCurve,arms=3',
'QuintetCurve,arms=4',
'QuintetCentres',
'QuintetCentres,arms=2',
'QuintetCentres,arms=3',
'QuintetCentres,arms=4',
'PyramidRows',
'PyramidRows,step=0',
'PyramidRows,step=1',
'PyramidRows,step=3',
'PyramidRows,step=37',
'PyramidRows,align=right',
'PyramidRows,align=right,step=0',
'PyramidRows,align=right,step=1',
'PyramidRows,align=right,step=3',
'PyramidRows,align=right,step=37',
'PyramidRows,align=left',
'PyramidRows,align=left,step=0',
'PyramidRows,align=left,step=1',
'PyramidRows,align=left,step=3',
'PyramidRows,align=left,step=37',
'GreekKeySpiral',
'GreekKeySpiral,turns=0',
'GreekKeySpiral,turns=1',
'GreekKeySpiral,turns=3',
'GreekKeySpiral,turns=4',
'GreekKeySpiral,turns=5',
'GreekKeySpiral,turns=6',
'GreekKeySpiral,turns=7',
'GreekKeySpiral,turns=8',
'GreekKeySpiral,turns=37',
'AlternatePaperMidpoint',
'AlternatePaperMidpoint,arms=2',
'AlternatePaperMidpoint,arms=3',
'AlternatePaperMidpoint,arms=4',
'AlternatePaperMidpoint,arms=5',
'AlternatePaperMidpoint,arms=6',
'AlternatePaperMidpoint,arms=7',
'AlternatePaperMidpoint,arms=8',
'AlternatePaper',
'AlternatePaper,arms=2',
'AlternatePaper,arms=3',
'AlternatePaper,arms=4',
'AlternatePaper,arms=5',
'AlternatePaper,arms=6',
'AlternatePaper,arms=7',
'AlternatePaper,arms=8',
'WythoffArray',
'PowerArray',
'PowerArray,radix=3',
'PowerArray,radix=4',
'Diagonals',
'Diagonals,direction=up',
'DiagonalsOctant',
'DiagonalsOctant,direction=up',
'DiagonalsAlternating',
'TerdragonMidpoint',
'TerdragonMidpoint,arms=1',
'TerdragonMidpoint,arms=2',
'TerdragonMidpoint,arms=6',
'TerdragonCurve',
'TerdragonCurve,arms=1',
'TerdragonCurve,arms=2',
'TerdragonCurve,arms=6',
'TerdragonRounded',
'TerdragonRounded,arms=1',
'TerdragonRounded,arms=2',
'TerdragonRounded,arms=6',
'CCurve',
'R5DragonMidpoint',
'R5DragonMidpoint,arms=2',
'R5DragonMidpoint,arms=3',
'R5DragonMidpoint,arms=4',
'R5DragonCurve',
'R5DragonCurve,arms=2',
'R5DragonCurve,arms=3',
'R5DragonCurve,arms=4',
'ImaginaryHalf',
'ImaginaryBase',
'CubicBase',
'GrayCode',
'WunderlichSerpentine',
'WunderlichSerpentine,serpentine_type=100_000_000',
'WunderlichSerpentine,serpentine_type=000_000_001',
'WunderlichSerpentine,radix=2',
'WunderlichSerpentine,radix=4',
'WunderlichSerpentine,radix=5,serpentine_type=coil',
'CretanLabyrinth',
'OctagramSpiral',
'AnvilSpiral',
'AnvilSpiral,wider=1',
'AnvilSpiral,wider=2',
'AnvilSpiral,wider=9',
'AnvilSpiral,wider=17',
'AR2W2Curve',
'AR2W2Curve,start_shape=D2',
'AR2W2Curve,start_shape=B2',
'AR2W2Curve,start_shape=B1rev',
'AR2W2Curve,start_shape=D1rev',
'AR2W2Curve,start_shape=A2rev',
'BetaOmega',
'KochelCurve',
'CincoCurve',
'HilbertSpiral',
'HilbertCurve',
'LTiling',
'LTiling,L_fill=ends',
'LTiling,L_fill=all',
'MPeaks', # but not across gap
'WunderlichMeander',
'FibonacciWordFractal',
# 'CornerReplicate', # not defined yet
'DigitGroups',
'PeanoCurve',
'ZOrderCurve',
'HIndexing',
'SierpinskiCurve',
'SierpinskiCurveStair',
'DiamondArms',
'SquareArms',
'HexArms',
# 'UlamWarburton', # not really defined yet
# 'UlamWarburtonQuarter', # not really defined yet
'CellularRule54', # but not across gap
# 'CellularRule57', # but not across gap
# 'CellularRule57,mirror=1', # but not across gap
'CellularRule190', # but not across gap
'CellularRule190,mirror=1', # but not across gap
'Rows',
'Columns',
'SquareSpiral',
'DiamondSpiral',
'PentSpiral',
'PentSpiralSkewed',
'HexSpiral',
'HexSpiralSkewed',
'HeptSpiralSkewed',
'TriangleSpiral',
'TriangleSpiralSkewed',
'TriangleSpiralSkewed,skew=right',
'TriangleSpiralSkewed,skew=up',
'TriangleSpiralSkewed,skew=down',
# 'SacksSpiral', # sin/cos
# 'TheodorusSpiral', # counting by N
# 'ArchimedeanChords', # counting by N
# 'VogelFloret', # sin/cos
'KnightSpiral',
'SierpinskiArrowheadCentres',
'SierpinskiArrowheadCentres,align=right',
'SierpinskiArrowheadCentres,align=left',
'SierpinskiArrowheadCentres,align=diagonal',
'SierpinskiArrowhead',
'SierpinskiArrowhead,align=right',
'SierpinskiArrowhead,align=left',
'SierpinskiArrowhead,align=diagonal',
# 'SierpinskiTriangle', # fracs not really defined yet
'QuadricCurve',
'QuadricIslands',
'DragonRounded',
'DragonMidpoint',
'DragonCurve',
'KochSquareflakes',
'KochSnowflakes',
'KochCurve',
'KochPeaks',
'FlowsnakeCentres',
'GosperReplicate',
'GosperSide',
'GosperIslands',
'Flowsnake',
# 'DivisibleColumns', # counting by N
# 'DivisibleColumns,divisor_type=proper',
# 'CoprimeColumns', # counting by N
# 'DiagonalRationals',# counting by N
# 'GcdRationals', # counting by N
# 'GcdRationals,pairs_order=rows_reverse',
# 'GcdRationals,pairs_order=diagonals_down',
# 'GcdRationals,pairs_order=diagonals_up',
# 'FactorRationals', # counting by N
# 'TriangularHypot', # counting by N
# 'TriangularHypot,points=odd',
# 'TriangularHypot,points=all',
# 'TriangularHypot,points=hex',
# 'TriangularHypot,points=hex_rotated',
# 'TriangularHypot,points=hex_centred',
'PythagoreanTree',
# 'Hypot', # searching by N
# 'HypotOctant', # searching by N
# 'PixelRings', # searching by N
# 'FilledRings', # searching by N
# 'MultipleRings', # sin/cos, maybe
'QuintetReplicate',
'SquareReplicate',
'ComplexPlus',
'ComplexMinus',
'ComplexRevolving',
# 'File', # not applicable
'Corner',
'PyramidSides',
'Staircase',
'StaircaseAlternating',
'StaircaseAlternating,end_type=square',
);
my @classes = map {"Math::PlanePath::$_"} @modules;
sub module_parse {
my ($mod) = @_;
my ($class, @parameters) = split /,/, $mod;
return ("Math::PlanePath::$class",
map {/(.*?)=(.*)/ or die; ($1 => $2)} @parameters);
}
foreach my $module (@modules) {
### $module
my ($class, %parameters) = module_parse($module);
eval "require $class" or die;
my $path = $class->new (width => 23,
height => 17);
my $arms = $path->arms_count;
my $n = Math::BigRat->new(2) ** 256 + 3;
if ($path->isa('Math::PlanePath::CellularRule190')) {
$n += 1; # not across gap
}
my $frac = Math::BigRat->new('1/3');
my $n_frac = $frac + $n;
my $orig = $n_frac->copy;
my ($x1,$y1) = $path->n_to_xy($n);
### xy1: "$x1,$y1"
my ($x2,$y2) = $path->n_to_xy($n+$arms);
### xy2: "$x2,$y2"
my $dx = $x2 - $x1;
my $dy = $y2 - $y1;
### dxy: "$dx, $dy"
my $want_x = $frac * Math::BigRat->new ($dx) + $x1;
my $want_y = $frac * Math::BigRat->new ($dy) + $y1;
my ($x_frac,$y_frac) = $path->n_to_xy($n_frac);
### xy frac: "$x_frac, $y_frac"
ok ("$x_frac", "$want_x", "$module arms=$arms X frac=$frac dxdy=$dx,$dy arms=$arms");
ok ("$y_frac", "$want_y", "$module arms=$arms Y frac=$frac dxdy=$dx,$dy arms=$arms");
}
exit 0;
Math-PlanePath-113/xt/pod-lists.t 0000644 0001750 0001750 00000015473 12155214047 014450 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Check that the supported fields described in each pod matches what the
# code says.
use 5.005;
use strict;
use FindBin;
use ExtUtils::Manifest;
use List::Util 'max';
use File::Spec;
use Test::More;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Smart::Comments;
# new in 5.6, so unless got it separately with 5.005
eval { require Pod::Parser }
or plan skip_all => "Pod::Parser not available -- $@";
plan tests => 6;
my $toplevel_dir = File::Spec->catdir ($FindBin::Bin, File::Spec->updir);
my $manifest_file = File::Spec->catfile ($toplevel_dir, 'MANIFEST');
my $manifest = ExtUtils::Manifest::maniread ($manifest_file);
my @lib_modules
= map {m{^lib/Math/PlanePath/([^/]+)\.pm$} ? $1 : ()} keys %$manifest;
@lib_modules = sort @lib_modules;
diag "module count ",scalar(@lib_modules);
#------------------------------------------------------------------------------
{
open FH, 'lib/Math/PlanePath.pm' or die $!;
my $content = do { local $/; }; # slurp
close FH or die;
### $content
{
$content =~ /=for my_pod see_also begin(.*)=for my_pod see_also end/s
or die "see_also not matched";
my $see_also = $1;
my @see_also;
while ($see_also =~ /L]+)>/g) {
push @see_also, $1;
}
@see_also = sort @see_also;
my $s = join(', ',@see_also);
my $l = join(', ',@lib_modules);
is ($s, $l, 'PlanePath.pm pod SEE ALSO');
my $j = "$s\n$l";
$j =~ /^(.*)(.*)\n\1(.*)/ or die;
my $sd = $2;
my $ld = $3;
if ($sd) {
diag "see also: ",$sd;
diag "library: ",$ld;
}
}
{
$content =~ /=for my_pod list begin(.*)=for my_pod list end/s
or die "class list not matched";
my $list = $1;
my @list;
while ($list =~ /^ (\S+)/mg) {
push @list, $1;
}
@list = sort @list;
my $s = join(', ',@list);
my $l = join(', ',@lib_modules);
is ($s, $l, 'PlanePath.pm pod class list');
my $j = "$s\n$l";
$j =~ /^(.*)(.*)\n\1(.*)/ or die;
my $sd = $2;
my $ld = $3;
if ($sd) {
diag "list: ",$sd;
diag "library: ",$ld;
}
}
{
$content =~ /=for my_pod step begin(.*)=for my_pod step end/s
or die "base list not matched";
my $list = $1;
$content =~ /=for my_pod base begin(.*)=for my_pod base end/s
or die "step list not matched";
$list .= $1;
# initialized to exceptions, no "step" in the pod
my @list = ('File',
'Hypot', 'HypotOctant',
'TriangularHypot', 'VogelFloret',
'PythagoreanTree', 'RationalsTree', 'FractionsTree', 'ChanTree',
'FactorRationals', 'GcdRationals', 'CfracDigits');
my %seen;
while ($list =~ /([A-Z]\S+)/g) {
my $elem = $1;
next if $elem eq 'Base';
next if $elem eq 'Path';
next if $elem eq 'Step';
next if $elem eq 'Fibonacci';
next if $elem eq 'ToothpickSpiral'; # separate Math-PlanePath-Toothpick
$elem =~ s/,//;
next if $seen{$elem}++;
push @list, $elem;
}
@list = sort @list;
my $s = join(', ',@list);
my $l = join(', ',@lib_modules);
is ($s, $l, 'PlanePath.pm step/base pod lists');
my $j = "$s\n$l";
$j =~ /^(.*)(.*)\n\1(.*)/ or die;
my $sd = $2;
my $ld = $3;
if ($sd) {
diag "list: ",$sd;
diag "library: ",$ld;
}
}
}
#------------------------------------------------------------------------------
foreach my $tfile ('xt/PlanePath-subclasses.t',
'xt/slow/NumSeq-PlanePathCoord.t',
) {
open FH, $tfile or die "$tfile: $!";
my $content = do { local $/; }; # slurp
close FH or die;
### $content
{
$content =~ /# module list begin(.*)module list end/s
or die "module list not matched";
my $list = $1;
my @list;
my %seen;
while ($list =~ /'([A-Z][^',]+)/ig) {
next if $seen{$1}++;
push @list, $1;
}
@list = sort @list;
my $s = join(', ',@list);
my $l = join(', ',@lib_modules);
is ($s, $l, $tfile);
my $j = "$s\n$l";
$j =~ /^(.*)(.*)\n\1(.*)/ or die;
my $sd = $2;
my $ld = $3;
if ($sd) {
diag "t list: ",$sd;
diag "library: ",$ld;
}
}
if ($tfile eq 't/PlanePath-subclasses.t') {
$content =~ /# rect_to_n_range exact begin(.*)# rect_to_n_range exact /s
or die "rect_to_n_range exact not matched";
my $list = $1;
my %exact;
while ($list =~ /^\s*'Math::PlanePath::([A-Z][^']+)/img) {
$exact{$1} = 1;
}
my $good = 1;
foreach my $module (@lib_modules) {
next if $module eq 'Flowsnake'; # inherited
next if $module eq 'QuintetCurve'; # inherited
my $file = module_exact($module);
my $t = $exact{$module} || 0;
if ($file != $t) {
diag "Math::PlanePath::$module file $file t $t";
$good = 0;
}
}
ok ($good,
"$tfile rect exact matches file comments");
sub module_exact {
my ($module) = @_;
my $filename = "lib/Math/PlanePath/$module.pm";
open FH, $filename or die $!;
my $content = do { local $/; }; # slurp
close FH or die;
### $content
$content =~ /^# (not )?exact\n(sub rect_to_n_range |\*rect_to_n_range =)/m
or die "$filename no exact comment";
return $1 ? 0 : 1;
}
}
}
#------------------------------------------------------------------------------
# numbers.pl
{
open FH, 'examples/numbers.pl' or die $!;
my $content = do { local $/; }; # slurp
close FH or die;
### $content
{
$content =~ /my \@all_classes = \((.*)# expand arg "all"/s
or die "module list not matched";
my $list = $1;
my @list = ('File');
my %seen;
while ($list =~ /'([A-Z][^',]+)/ig) {
next if $seen{$1}++;
push @list, $1;
}
@list = sort @list;
my $s = join(', ',@list);
my $l = join(', ',@lib_modules);
is ($s, $l, 'numbers.pl all_classes');
my $j = "$s\n$l";
$j =~ /^(.*)(.*)\n\1(.*)/ or die;
my $sd = $2;
my $ld = $3;
if ($sd) {
diag "numbers.pl list: ",$sd;
diag "library: ",$ld;
}
}
}
exit 0;
Math-PlanePath-113/xt/0-file-is-part-of.t 0000644 0001750 0001750 00000005766 12136177231 015573 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# 0-file-is-part-of.t is shared by several distributions.
#
# 0-file-is-part-of.t 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, or (at your option) any
# later version.
#
# 0-file-is-part-of.t 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 file. If not, see .
require 5;
use strict;
use Test::More tests => 1;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
ok (Test::FileIsPartOfDist->check(verbose=>1),
'Test::FileIsPartOfDist');
exit 0;
package Test::FileIsPartOfDist;
BEGIN { require 5 }
use strict;
use ExtUtils::Manifest;
use File::Slurp;
sub import {
my $class = shift;
my $arg;
foreach $arg (@_) {
if ($arg eq '-test') {
require Test;
Test::plan(tests=>1);
is ($class->check, 1, 'Test::FileIsPartOfDist');
}
}
return 1;
}
sub new {
my $class = shift;
return bless { @_ }, $class;
}
sub check {
my $class = shift;
my $self = $class->new(@_);
my $manifest = ExtUtils::Manifest::maniread();
if (! $manifest) {
$self->diag("no MANIFEST perhaps");
return 0;
}
my @filenames = keys %$manifest;
my $distname = $self->makefile_distname;
if (! defined $distname) {
$self->diag("Oops, DISTNAME not found in Makefile");
return 0;
}
if ($self->{'verbose'}) {
$self->diag("DISTNAME $distname");
}
my $good = 1;
my $filename;
foreach $filename (@filenames) {
if (! $self->check_file_is_part_of($filename,$distname)) {
$good = 0;
}
}
return $good;
}
sub makefile_distname {
my ($self) = @_;
my $filename = "Makefile";
my $content = File::Slurp::read_file ($filename);
if (! defined $content) {
$self->diag("Cannot read $filename: $!");
return undef;
}
my $distname;
if ($content =~ /^DISTNAME\s*=\s*([^#\n]*)/m) {
$distname = $1;
$distname =~ s/\s+$//;
}
return $distname;
}
sub check_file_is_part_of {
my ($self, $filename, $distname) = @_;
my $content = File::Slurp::read_file ($filename);
if (! defined $content) {
$self->diag("Cannot read $filename: $!");
return 0;
}
$content =~ /([T]his file is part of[^\n]*)/i
or return 1;
my $got = $1;
if ($got =~ /[T]his file is part of \Q$distname/i) {
return 1;
}
$self->diag("$filename: $got");
$self->diag("expected DISTNAME: $distname");
return 0;
}
sub diag {
my $self = shift;
my $func = $self->{'diag_func'}
|| eval { Test::More->can('diag') }
|| \&_diag;
&$func(@_);
}
sub _diag {
my $msg = join('', map {defined($_)?$_:'[undef]'} @_)."\n";
$msg =~ s/^/# /mg;
print STDERR $msg;
}
Math-PlanePath-113/xt/oeis/ 0002755 0001750 0001750 00000000000 12255673733 013310 5 ustar gg gg Math-PlanePath-113/xt/oeis/Corner-oeis.t 0000644 0001750 0001750 00000016060 12164412302 015641 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 7;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Corner;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A027709 -- boundary length
{
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_n_to_dboundary {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my $dboundary = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dboundary -= 2*(defined $an && $an < $n);
}
return $dboundary;
}
}
MyOEIS::compare_values
(anum => 'A027709',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Corner->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, $boundary;
$boundary += path_n_to_dboundary($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A078633 -- grid sticks
{
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_n_to_dsticks {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my $dsticks = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dsticks -= (defined $an && $an < $n);
}
return $dsticks;
}
}
MyOEIS::compare_values
(anum => 'A078633',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Corner->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
$boundary += path_n_to_dsticks($path,$n);
push @got, $boundary;
}
return \@got;
});
#------------------------------------------------------------------------------
# A000290 -- N on X axis, perfect squares starting from 1
MyOEIS::compare_values
(anum => 'A000290',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::Corner->new;
for (my $x = 0; @got < $count; $x++) {
push @got, $path->xy_to_n ($x, 0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002061 -- N on X=Y diagonal, extra initial 1
MyOEIS::compare_values
(anum => 'A002061',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::Corner->new;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n ($i, $i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A060736 -- permutation, N by diagonals down
MyOEIS::compare_values
(anum => 'A060736',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $corner = Math::PlanePath::Corner->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy($n);
push @got, $corner->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A064788 -- permutation, inverse of N by diagonals down
MyOEIS::compare_values
(anum => 'A064788',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $corner = Math::PlanePath::Corner->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $corner->n_start; @got < $count; $n++) {
my ($x, $y) = $corner->n_to_xy($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A060734 -- permutation, N by diagonals upwards
MyOEIS::compare_values
(anum => 'A060734',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $corner = Math::PlanePath::Corner->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy($n);
push @got, $corner->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A064790 -- permutation, inverse of N by diagonals upwards
MyOEIS::compare_values
(anum => 'A064790',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $corner = Math::PlanePath::Corner->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $corner->n_start; @got < $count; $n++) {
my ($x, $y) = $corner->n_to_xy($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A004201 -- N for which Y<=X, half below diagonal
MyOEIS::compare_values
(anum => 'A004201',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Corner->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($x >= $y) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A020703 -- permutation transpose Y,X
MyOEIS::compare_values
(anum => 'A020703',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Corner->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A053188 -- abs(X-Y), distance to next higher pronic, wider=1, extra 0
MyOEIS::compare_values
(anum => 'A053188',
func => sub {
my ($count) = @_;
my @got = (0); # extra initial 0
my $path = Math::PlanePath::Corner->new (wider => 1);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, abs($x-$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CornerReplicate-oeis.t 0000644 0001750 0001750 00000004025 12136177302 017477 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CornerReplicate;
use Math::PlanePath::ZOrderCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $crep = Math::PlanePath::CornerReplicate->new;
my $zorder = Math::PlanePath::ZOrderCurve->new;
#------------------------------------------------------------------------------
# A048647 -- permutation N at transpose Y,X
MyOEIS::compare_values
(anum => 'A048647',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $crep->n_start; @got < $count; $n++) {
my ($x, $y) = $crep->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $crep->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163241 -- flip base-4 digits 2,3 maps to ZOrderCurve
MyOEIS::compare_values
(anum => 'A163241',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $crep->n_start; @got < $count; $n++) {
my ($x, $y) = $crep->n_to_xy ($n);
my $n = $zorder->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DigitGroups-oeis.t 0000644 0001750 0001750 00000005525 12141661307 016663 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 3;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DigitGroups;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# parity_bitwise() vs path
# X is low 0111..11 then Y above that, so (X^Y)&1 is
# Parity = lowbit(N) ^ bit_above_lowest_zero(N)
{
my $path = Math::PlanePath::DigitGroups->new;
my $bad = 0;
foreach my $n (0 .. 0xFFFF) {
my ($x, $y) = $path->n_to_xy ($n);
my $path_value = ($x + $y) % 2;
my $a_value = parity_bitwise($n);
if ($path_value != $a_value) {
MyTestHelpers::diag ("diff n=$n path=$path_value acalc=$a_value");
MyTestHelpers::diag (" xy=$x,$y");
last if ++$bad > 10;
}
}
ok ($bad, 0, "parity_bitwise()");
}
sub parity_bitwise {
my ($n) = @_;
return ($n & 1) ^ bit_above_lowest_zero($n);
}
sub bit_above_lowest_zero {
my ($n) = @_;
for (;;) {
if (($n % 2) == 0) {
last;
}
$n = int($n/2);
}
$n = int($n/2);
return ($n % 2);
}
#------------------------------------------------------------------------------
# A084472 - X axis in binary, excluding 0
MyOEIS::compare_values
(anum => 'A084472',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DigitGroups->new;
for (my $x = 1; @got < $count; $x++) {
my $n = $path->xy_to_n ($x,0);
push @got, to_binary($n);
}
return \@got;
});
sub to_binary {
my ($n) = @_;
return ($n < 0 ? '-' : '') . sprintf('%b', abs($n));
}
#------------------------------------------------------------------------------
# A060142 - X axis sorted
MyOEIS::compare_values
(anum => 'A060142',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DigitGroups->new;
for (my $x = 0; @got < 16 * $count; $x++) {
push @got, $path->xy_to_n ($x,0);
}
@got = sort {$a<=>$b} @got;
$#got = $count-1;
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/ComplexMinus-oeis.t 0000644 0001750 0001750 00000007206 12240240414 017034 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 5;
use Math::BigInt try => 'GMP';
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
use Math::PlanePath::ComplexMinus;
my $path = Math::PlanePath::ComplexMinus->new;
#------------------------------------------------------------------------------
# A052537 length A,B or C
# A003476 total boundary length / 2
# A203175 boundary length
MyOEIS::compare_values
(anum => 'A203175',
name => 'boundary length',
func => sub {
my ($count) = @_;
my @got = (1,1,2);
my $a = Math::BigInt->new(2);
my $b = Math::BigInt->new(2);
my $c = Math::BigInt->new(0);
while (@got < $count) {
push @got, ($a+$b+$c);
($a,$b,$c) = abc_step($a,$b,$c);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A003476',
name => 'boundary length / 2',
func => sub {
my ($count) = @_;
my @got = (1);
my $a = Math::BigInt->new(2);
my $b = Math::BigInt->new(2);
my $c = Math::BigInt->new(0);
while (@got < $count) {
push @got, ($a+$b+$c)/2;
($a,$b,$c) = abc_step($a,$b,$c);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A052537',
func => sub {
my ($count) = @_;
my @got = (1,0);
for (my $i = 0; @got < $count; $i++) {
my ($a,$b,$c) = abc_by_pow($i);
push @got, $c;
}
return \@got;
});
sub abc_step {
my ($a,$b,$c) = @_;
return ($a + 2*$c,
$a,
$b);
}
sub abc_by_pow {
my ($k) = @_;
my $zero = $k*0;
my $r = 1;
my $a = $zero + 2*$r;
my $b = $zero + 2;
my $c = $zero + 2*(1-$r);
foreach (1 .. $k) {
($a,$b,$c) = ((2*$r-1)*$a + 0 + 2*$r*$c,
($r*$r-2*$r+2)*$a + 0 + ($r-1)*($r-1)*$c,
0 + $b);
}
return ($a,$b,$c);
}
#------------------------------------------------------------------------------
# A066322 - N on X axis, diffs at 16k+3,16k+4
MyOEIS::compare_values
(anum => 'A066322',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i++) {
my $x = 16*$i+3;
my $x_next = 16*$i+4;
my $n = $path->xy_to_n ($x,0);
my $n_next = $path->xy_to_n ($x_next,0);
push @got, $n_next - $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A066323 - N on X axis, count 1 bits
MyOEIS::compare_values
(anum => 'A066323',
func => sub {
my ($count) = @_;
my @got = (0);
for (my $x = 1; @got < $count; $x++) {
my $n = $path->xy_to_n ($x,0);
push @got, count_1_bits($n);
}
return \@got;
});
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/UlamWarburtonQuarter-oeis.t 0000644 0001750 0001750 00000003101 12136177277 020571 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 6;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::UlamWarburtonQuarter;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A147610 - 3^(count 1-bits), width of depth level
MyOEIS::compare_values
(anum => 'A147610',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::UlamWarburtonQuarter->new;
my @got;
my $prev_depth = 0;
my $count = 0;
for (my $depth = 0; @got < $count; $depth++) {
push @got,
$path->tree_depth_to_n($depth+1)
- $path->tree_depth_to_n($depth);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/AlternatePaperMidpoint-oeis.t 0000644 0001750 0001750 00000003142 12153014541 021022 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::AlternatePaperMidpoint;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A016116 -- X/2 at N=2^k, starting k=1, being 2^floor(k/2)
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
MyOEIS::compare_values
(anum => 'A016116',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::AlternatePaperMidpoint->new;
my @got;
for (my $n = $bigclass->new(2); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x/2;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/KochSnowflakes-oeis.t 0000644 0001750 0001750 00000005045 12253200234 017331 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::KochSnowflakes;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A178789 - num acute angle turns, 4^n + 2
# A002446 - num obtuse angle turns, 2*4^n - 2
MyOEIS::compare_values
(anum => 'A002446',
max_value => 100_000,
func => sub {
my ($count) = @_;
my @got;
for (my $level = 0; @got < $count; $level++) {
my ($acute, $obtuse) = count_angles_in_level($level);
push @got, $obtuse;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A178789',
max_value => 100_000,
func => sub {
my ($count) = @_;
my @got;
for (my $level = 0; @got < $count; $level++) {
my ($acute, $obtuse) = count_angles_in_level($level);
push @got, $acute;
}
return \@got;
});
sub count_angles_in_level {
my ($level) = @_;
require Math::NumSeq::PlanePathTurn;
my $path = Math::PlanePath::KochSnowflakes->new;
my $n_level = 4**$level;
my $n_end = 4**($level+1) - 1;
my @x;
my @y;
foreach my $n ($n_level .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
push @x, $x;
push @y, $y;
}
my $acute = 0;
my $obtuse = 0;
foreach my $i (0 .. $#x) {
my $dx = $x[$i-1] - $x[$i-2];
my $dy = $y[$i-1] - $y[$i-2];
my $next_dx = $x[$i] - $x[$i-1];
my $next_dy = $y[$i] - $y[$i-1];
my $tturn6 = Math::NumSeq::PlanePathTurn::_turn_func_TTurn6($dx,$dy, $next_dx,$next_dy);
### $tturn6
if ($tturn6 == 2 || $tturn6 == 4) {
$acute++;
} else {
$obtuse++;
}
}
return ($acute, $obtuse);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/UlamWarburton-oeis.t 0000644 0001750 0001750 00000012153 12157015414 017217 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 7;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Devel::Comments '###';
use Math::PlanePath::UlamWarburton;
my $path = Math::PlanePath::UlamWarburton->new;
#------------------------------------------------------------------------------
# my @grid;
# my $offset = 30;
# my @n_start;
#
# my $prev = 0;
# $grid[0+$offset][0+$offset] = 0;
# foreach my $n (1 .. 300) {
# my ($x,$y) = $path->n_to_xy($n);
# my $l = $grid[$x+$offset-1][$y+$offset]
# || $grid[$x+$offset+1][$y+$offset]
# || $grid[$x+$offset][$y+$offset-1]
# || $grid[$x+$offset][$y+$offset+1]
# || 0;
# if ($l != $prev) {
# push @n_start, $n;
# $prev = $l;
# }
# $grid[$x+$offset][$y+$offset] = $l+1;
# }
# ### @n_start
# my @n_end = map {$_-1} @n_start;
# ### @n_end
#
# my @levelcells = (1, map {$n_start[$_]-$n_start[$_-1]} 1 .. $#n_start);
# ### @levelcells
# foreach my $y (reverse -$offset .. $offset) {
# foreach my $x (-$offset .. $offset) {
# my $c = $grid[$x+$offset][$y+$offset];
# if (! defined $c) { $c = ' '; }
# print $c;
# }
# print "\n";
# }
#------------------------------------------------------------------------------
# A183060 - count total cells in half plane, including axes
MyOEIS::compare_values
(anum => 'A183060',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::UlamWarburton->new (parts => '2',
n_start => 0);
my @got;
for (my $depth = 0; @got < $count; $depth++) {
push @got, $path->tree_depth_to_n($depth);
}
return \@got;
});
# added
MyOEIS::compare_values
(anum => 'A183061',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::UlamWarburton->new (parts => '2');
my @got = (0);
for (my $depth = 0; @got < $count; $depth++) {
push @got, $path->tree_depth_to_width($depth);
}
return \@got;
});
#------------------------------------------------------------------------------
# A151922 - count total cells in first quadrant, incl X,Y axes
MyOEIS::compare_values
(anum => 'A151922',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::UlamWarburton->new (parts => '1');
my @got;
for (my $depth = 0; @got < $count; $depth++) {
push @got, $path->tree_depth_to_n_end($depth);
}
return \@got;
});
# added
MyOEIS::compare_values
(anum => 'A079314',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::UlamWarburton->new (parts => '1');
my @got;
for (my $depth = 0; @got < $count; $depth++) {
push @got, $path->tree_depth_to_width($depth);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A151922',
func => sub {
my ($count) = @_;
my @got;
my $n = $path->n_start;
my $total = 0;
for (my $depth = 0; @got < $count; $depth++) {
my $n_end = $path->tree_depth_to_n_end($depth);
for ( ; $n <= $n_end; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($x >= 0 && $y >= 0) {
$total++;
}
}
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A079314 - count added cells in first quadrant, incl X,Y axes
# is added(depth)/4 + 1, the +1 being for two axes
#
MyOEIS::compare_values
(anum => 'A079314',
func => sub {
my ($count) = @_;
my @got;
my $n = $path->n_start;
for (my $depth = 0; @got < $count; $depth++) {
my $n_end = $path->tree_depth_to_n_end($depth);
my $added = 0;
for ( ; $n <= $n_end; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($x >= 0 && $y >= 0) {
$added++;
}
}
push @got, $added;
}
return \@got;
});
#------------------------------------------------------------------------------
# A147582 - count new cells in each level
MyOEIS::compare_values
(anum => 'A147582',
func => sub {
my ($count) = @_;
my @got;
my $prev = $path->tree_depth_to_n(0);
for (my $depth = 1; @got < $count; $depth++) {
my $n = $path->tree_depth_to_n($depth);
push @got, $n - $prev;
$prev = $n;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/KnightSpiral-oeis.t 0000644 0001750 0001750 00000007350 12136177300 017017 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 8;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
use Math::PlanePath::KnightSpiral;
use Math::PlanePath::SquareSpiral;
my $knight = Math::PlanePath::KnightSpiral->new;
my $square = Math::PlanePath::SquareSpiral->new;
#------------------------------------------------------------------------------
# A068608 - N values in square spiral order, same first step
MyOEIS::compare_values
(anum => 'A068608',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068609 - rotate 90 degrees
MyOEIS::compare_values
(anum => 'A068609',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
### knight: "$n $x,$y"
($x, $y) = (-$y, $x);
push @got, $square->xy_to_n ($x, $y);
### rotated: "$x,$y"
### is: "got[$#got] = $got[-1]"
}
return \@got;
});
# A068610 - rotate 180 degrees
MyOEIS::compare_values
(anum => 'A068610',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
($x, $y) = (-$x, -$y);
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068611 - rotate 270 degrees
MyOEIS::compare_values
(anum => 'A068611',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
($x, $y) = ($y, -$x);
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068612 - rotate 180 degrees, opp direction, being X negated
MyOEIS::compare_values
(anum => 'A068612',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
$x = -$x;
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068613 -
MyOEIS::compare_values
(anum => 'A068613',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
($x, $y) = (-$y, -$x);
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068614 - clockwise, Y negated
MyOEIS::compare_values
(anum => 'A068614',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
$y = -$y;
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
# A068615 - transpose
MyOEIS::compare_values
(anum => 'A068615',
func => sub {
my ($count) = @_;
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $knight->n_to_xy ($n);
($y, $x) = ($x, $y);
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
exit 0;
Math-PlanePath-113/xt/oeis/DragonCurve-oeis.t 0000644 0001750 0001750 00000042720 12136177227 016647 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 18;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DragonCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $dragon = Math::PlanePath::DragonCurve->new;
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
# with Y reckoned increasing upwards
sub dxdy_to_direction {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # north
if ($dy < 0) { return 3; } # south
}
# return 1 for left, 0 for right
sub path_n_turn {
my ($path, $n) = @_;
my $prev_dir = path_n_dir ($path, $n-1);
my $dir = path_n_dir ($path, $n);
my $turn = ($dir - $prev_dir) % 4;
if ($turn == 1) { return 1; }
if ($turn == 3) { return 0; }
die "Oops, unrecognised turn";
}
# return 0,1,2,3
sub path_n_dir {
my ($path, $n) = @_;
my ($dx,$dy) = $path->n_to_dxdy($n)
or die "Oops, no point at ",$n;
return dxdy_to_dir ($dx, $dy);
}
# return 0,1,2,3, with Y reckoned increasing upwards
sub dxdy_to_dir {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # north
if ($dy < 0) { return 3; } # south
}
#------------------------------------------------------------------------------
# A038189 -- bit above lowest 1, is 0=left,1=right
MyOEIS::compare_values
(anum => 'A038189',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'DragonCurve',
turn_type => 'Right');
my @got = (0); # extra initial 0
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
# A089013=A038189 but initial extra 1
MyOEIS::compare_values
(anum => 'A089013',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'DragonCurve',
turn_type => 'Right');
my @got = (1); # extra initial 1
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A126937 -- points numbered as SquareSpiral, starting N=0
{
my $anum = 'A126937';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
require Math::PlanePath::SquareSpiral;
my $square = Math::PlanePath::SquareSpiral->new (n_start => 0);
for (my $n = $dragon->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $dragon->n_to_xy ($n);
my $square_n = $square->xy_to_n ($x, -$y);
push @got, $square_n;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A082410 -- complement reversal, is 1=left, 0=right
{
my $anum = 'A082410';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
push @got, 0;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
push @got, path_n_turn($dragon,$n); # 1=left,0=right
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- reversal complement");
}
#------------------------------------------------------------------------------
# A003460 -- turn 1=left,0=right packed as octal high to low, in 2^n levels
{
my $anum = 'A003460';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
require Math::BigInt;
my $bits = Math::BigInt->new(0);
my $target_n_level = 2;
my $n = 1;
while (@got < @$bvalues) {
if ($n >= $target_n_level) { # not including n=2^level point itself
my $octal = $bits->as_oct; # new enough Math::BigInt
$octal =~ s/^0+//; # strip leading "0"
push @got, Math::BigInt->new("$octal");
$target_n_level *= 2;
}
my $turn = path_n_turn($dragon,$n++);
my $bit;
if ($turn == 1) { # left
$bit = 1;
} elsif ($turn == 0) { # right
$bit = 0;
} else {
die "Oops, unrecognised turn $turn";
}
$bits = 2*$bits + $bit;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..$#$bvalues]));
MyTestHelpers::diag ("got: ",join(',',@got[0..$#got]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction 1,3");
}
#------------------------------------------------------------------------------
# A099545 -- relative direction 1=left, 3=right
{
my $anum = 'A099545';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
push @got, 1;
} elsif ($turn == 0) { # right
push @got, 3;
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction 1,3");
}
#------------------------------------------------------------------------------
# A007400 - 2 * run lengths, extra initial 0,1
{
my $anum = 'A007400';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $prev_turn = path_n_turn($dragon,1);
my $run = 1; # count for initial $prev_turn
push @got, 0,1;
for (my $n = 2; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == $prev_turn) {
$run++;
} else {
push @got, 2 * $run;
$run = 1; # count for new $turn value
}
$prev_turn = $turn;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- 2 * turn run lengths");
}
#------------------------------------------------------------------------------
# A088431 - dragon turns run lengths
{
my $anum = 'A088431';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $prev_turn = path_n_turn($dragon,1);
my $run = 1; # count for initial $prev_turn
for (my $n = 2; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == $prev_turn) {
$run++;
} else {
push @got, $run;
$run = 1; # count for new $turn value
}
$prev_turn = $turn;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- turn run lengths");
}
#------------------------------------------------------------------------------
# A014707 -- relative direction 1=left, 0=right, starting from 1
{
my $anum = 'A014707';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
push @got, 0;
} elsif ($turn == 0) { # right
push @got, 1;
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A014710 -- relative direction 2=left, 1=right
{
my $anum = 'A014710';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
push @got, 2;
} elsif ($turn == 0) { # right
push @got, 1;
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A014709 -- relative direction 1=left, 2=right
{
my $anum = 'A014709';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
push @got, 1;
} elsif ($turn == 0) { # right
push @got, 2;
} else {
die "Oops, unrecognised turn $turn";
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A014577 -- relative direction 0=left, 1=right, starting from 1
#
# cf A059125 is almost but not quite the same, the 8,24,or some such entries
# differ
{
my $anum = 'A014577';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
push @got, path_n_turn($dragon,$n);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A166242 - doubling/halving, is 2^(total turn)
{
my $anum = 'A166242';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
push @got, 1;
my $cumulative = 1;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) {
$cumulative *= 2;
} elsif ($turn == 0) {
$cumulative /= 2;
} else {
die;
}
push @got, $cumulative;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- cumulative turn");
}
#------------------------------------------------------------------------------
# A088748 - dragon cumulative turn +/-1
{
my $anum = 'A088748';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 1;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
push @got, $cumulative;
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
$cumulative += 1;
} elsif ($turn == 0) { # right
$cumulative -= 1;
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- cumulative +/-1 turn");
}
#------------------------------------------------------------------------------
# A112347 - Kronecker -1/n is 1=left,-1=right, extra initial 0
{
my $anum = 'A112347';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
push @got, 0;
for (my $n = 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) {
push @got, 1; # left
} elsif ($turn == 0) {
push @got, -1; # right
} else {
die;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- Kronecker -1/n");
}
#------------------------------------------------------------------------------
# A121238 - -1 power something is 1=left,-1=right, extra initial 1
# A088585
# A088575
# A088567 a(0)=1, a(1)=1;
# for m >= 1, a(2m) = a(2m-1) + a(m) - 1,
# a(2m+1) = a(2m) + 1
# A090678 = A088567 mod 2.
#
{
my $anum = 'A121238';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
push @got, 1;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) {
push @got, 1; # left
} elsif ($turn == 0) {
push @got, -1; # right
} else {
die;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- -1 power something");
}
#------------------------------------------------------------------------------
# A164910 - dragon cumulative turn +/-1, then partial sums
{
my $anum = 'A164910';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 1;
my $partial_sum = $cumulative;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
push @got, $partial_sum;
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
$cumulative += 1;
} elsif ($turn == 0) { # right
$cumulative -= 1;
} else {
die "Oops, unrecognised turn $turn";
}
$partial_sum += $cumulative;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@$bvalues));
MyTestHelpers::diag ("got: ",join(',',@got));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- partial sums cumulative turn");
}
#------------------------------------------------------------------------------
# A091072 -- N positions of left turns
{
my $anum = 'A091072';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
push @got, $n;
} elsif ($turn == 0) { # right
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- left turn N positions");
}
#------------------------------------------------------------------------------
# A005811 -- total rotation, count runs of bits in binary
{
my $anum = 'A005811';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 0;
for (my $n = $dragon->n_start + 1; @got < @$bvalues; $n++) {
push @got, $cumulative;
my $turn = path_n_turn($dragon,$n);
if ($turn == 1) { # left
$cumulative += 1;
} elsif ($turn == 0) { # right
$cumulative -= 1;
} else {
die "Oops, unrecognised turn $turn";
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- total rotation");
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CellularRule190-oeis.t 0000644 0001750 0001750 00000006172 12136177302 017250 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CellularRule190;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A071039 - 0/1 by rows rule 190
MyOEIS::compare_values
(anum => 'A071039',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CellularRule190->new;
my @got;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A118111 - 0/1 by rows rule 190 (duplicate)
MyOEIS::compare_values
(anum => 'A118111',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CellularRule190->new;
my @got;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A037576 - rows as rule 190 binary bignums (base 4 periodic ...)
MyOEIS::compare_values
(anum => 'A037576',
func => sub {
my ($count) = @_;
require Math::BigInt;
my $path = Math::PlanePath::CellularRule190->new;
my @got;
my $y = 0;
while (@got < $count) {
my $b = 0;
foreach my $i (0 .. 2*$y+1) {
if ($path->xy_is_visited ($y-$i, $y)) {
$b += Math::BigInt->new(2) ** $i;
}
}
push @got, "$b";
$y++;
}
return \@got;
});
#------------------------------------------------------------------------------
# A071041 - 0/1 rule 246
MyOEIS::compare_values
(anum => 'A071041',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CellularRule190->new (mirror => 1);
my @got;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/LTiling-oeis.t 0000644 0001750 0001750 00000005073 12142120511 015747 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::LTiling;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A112539 -- X+Y mod 2
MyOEIS::compare_values
(anum => 'A112539',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::LTiling->new (L_fill => 'left');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, ($x+$y)%2;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A112539',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::LTiling->new (L_fill => 'upper');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, ($x+$y)%2;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A112539',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::LTiling->new (L_fill => 'middle');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, ($x+$y+1)%2;
}
return \@got;
});
#------------------------------------------------------------------------------
# A048647 -- N at transpose Y,X
MyOEIS::compare_values
(anum => 'A048647',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::LTiling->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/NumSeq-PlanePath-oeis.t 0000644 0001750 0001750 00000027356 12234034641 017511 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Check PlanePathCoord etc sequences against OEIS data.
#
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
# use Smart::Comments '###';
sub want_anum {
my ($anum) = @_;
# return 0 unless $anum =~ /A062157/;
# return 0 unless $anum =~ /A151922|A183060/;
# return 0 unless $anum =~ /A177702|A102283|A131756/;
return 1;
}
sub want_planepath {
my ($planepath) = @_;
return 0 unless $planepath =~ /FactorRationals/;
# return 0 unless $planepath =~ /Octag|Pent|Hept/;
# return 0 unless $planepath =~ /Divis|DiagonalRationals|CoprimeCol/;
# return 0 unless $planepath =~ /DiamondSpiral/;
# return 0 unless $planepath =~ /LCorner/;
# return 0 unless $planepath =~ /LCorn|RationalsTree/;
# return 0 unless $planepath =~ /^Corner$/i;
# return 0 unless $planepath =~ /SierpinskiArrowheadC/;
# return 0 unless $planepath =~ /TriangleSpiralSkewed/;
# return 0 unless $planepath =~ /^Rows/;
# return 0 unless $planepath =~ /DiagonalRationals/;
# return 0 unless $planepath =~ /ToothpickSpiral/;
return 1;
}
sub want_coordinate {
my ($type) = @_;
# return 0 unless $type =~ /^dR/;
# return 0 unless $type =~ /^Abs[XY]/;
# return 0 unless $type =~ /DiffYX/i;
# return 0 unless $type =~ /^Depth/;
# return 0 unless $type =~ /SLR|SRL|LSR/;
return 1;
}
#------------------------------------------------------------------------------
# use POSIX ();
# use constant DBL_INT_MAX => (POSIX::FLT_RADIX() ** POSIX::DBL_MANT_DIG());
# use constant MY_MAX => (POSIX::FLT_RADIX() ** (POSIX::DBL_MANT_DIG()-5));
sub _delete_duplicates {
my ($arrayref) = @_;
my %seen;
@seen{@$arrayref} = ();
@$arrayref = sort {$a<=>$b} keys %seen;
}
sub _min {
my $ret = shift;
while (@_) {
my $next = shift;
if ($ret > $next) {
$ret = $next;
}
}
return $ret;
}
sub _max {
my $ret = shift;
while (@_) {
my $next = shift;
if ($next > $ret) {
$ret = $next;
}
}
return $ret;
}
my %duplicate_anum = (A021015 => 'A010680',
A081274 => 'A038764',
);
#------------------------------------------------------------------------------
my $good = 1;
my $total_checks = 0;
sub check_class {
my ($anum, $class, $parameters) = @_;
### check_class() ...
### $class
### $parameters
my %parameters = @$parameters;
# return unless $class =~ /PlanePathTurn/;
# return unless $parameters{'planepath'} =~ /DiagonalRat/i;
# return unless $parameters{'planepath'} =~ /AlternateP/;
# return unless $parameters{'planepath'} =~ /Peano/;
# return unless $parameters{'planepath'} =~ /PyramidRows/;
# return unless $parameters{'planepath'} =~ /Fib/;
# return unless $parameters{'planepath'} =~ /TriangleSpiralSkewed/;
return unless want_anum($anum);
return unless want_planepath($parameters{'planepath'}
|| '');
return unless want_coordinate($parameters{'coordinate_type'}
|| $parameters{'delta_type'}
|| $parameters{'line_type'}
|| $parameters{'turn_type'}
|| '');
eval "require $class" or die;
my $name = join(',',
$class,
map {defined $_ ? $_ : '[undef]'} @$parameters);
my $max_count = undef;
if ($anum eq 'A038567'
|| $anum eq 'A038566'
|| $anum eq 'A020652'
|| $anum eq 'A020653') {
# CoprimeColumns, DiagonalRationals shortened for now
$max_count = 10000;
} elsif ($anum eq 'A051132') {
# Hypot
$max_count = 1000;
}
my ($want, $want_i_start) = MyOEIS::read_values ($anum,
max_count => $max_count)
or do {
MyTestHelpers::diag("skip $anum $name, no file data");
return;
};
### read_values len: scalar(@$want)
### $want_i_start
if ($anum eq 'A009003') {
# PythagoreanHypots slow, only first 250 values for now ...
splice @$want, 250;
} elsif ($anum eq 'A003434') {
# TotientSteps slow, only first 250 values for now ...
splice @$want, 250;
} elsif ($anum eq 'A005408') { # odd numbers
# shorten for CellularRule rule=84 etc
splice @$want, 500;
}
my $want_count = scalar(@$want);
MyTestHelpers::diag ("$anum $name ($want_count values to $want->[-1])");
my $hi = $want->[-1];
if ($hi < @$want) {
$hi = @$want;
}
### $hi
# hi => $hi
my $seq = $class->new (@$parameters);
### seq class: ref $seq
if ($seq->isa('Math::NumSeq::OEIS::File')) {
die "Oops, not meant to exercies $seq";
}
{
### $seq
my $got_anum = $seq->oeis_anum;
if (! defined $got_anum) {
$got_anum = 'undef';
}
my $want_anum = $duplicate_anum{$anum} || $anum;
if ($got_anum ne $want_anum) {
$good = 0;
MyTestHelpers::diag ("bad: $name");
MyTestHelpers::diag ("got anum $got_anum");
MyTestHelpers::diag ("want anum $want_anum");
MyTestHelpers::diag (ref $seq);
}
}
{
my $got_i_start = $seq->i_start;
if (! defined $want_i_start) {
MyTestHelpers::diag ("skip i_start check: \"stripped\" values only");
} elsif ($got_i_start != $want_i_start
&& $anum ne 'A000004' # offset=0, but allow other i_start here
&& $anum ne 'A000012' # offset=0, but allow other i_start here
) {
$good = 0;
MyTestHelpers::diag ("bad: $name");
MyTestHelpers::diag ("got i_start ",$got_i_start);
MyTestHelpers::diag ("want i_start ",$want_i_start);
}
}
{
### by next() ...
my @got;
my $got = \@got;
while (my ($i, $value) = $seq->next) {
push @got, $value;
if (@got >= @$want) {
last;
}
}
my $diff = MyOEIS::diff_nums($got, $want);
if (defined $diff) {
$good = 0;
MyTestHelpers::diag ("bad: $name by next() hi=$hi");
MyTestHelpers::diag ($diff);
MyTestHelpers::diag (ref $seq);
MyTestHelpers::diag ("got len ".scalar(@$got));
MyTestHelpers::diag ("want len ".scalar(@$want));
if ($#$got > 200) { $#$got = 200 }
if ($#$want > 200) { $#$want = 200 }
MyTestHelpers::diag ("got ". join(',', map {defined() ? $_ : 'undef'} @$got));
MyTestHelpers::diag ("want ". join(',', map {defined() ? $_ : 'undef'} @$want));
}
}
{
### by next() after rewind ...
$seq->rewind;
my @got;
my $got = \@got;
while (my ($i, $value) = $seq->next) {
# ### $i
# ### $value
push @got, $value;
if (@got >= @$want) {
last;
}
}
my $diff = MyOEIS::diff_nums($got, $want);
if (defined $diff) {
$good = 0;
MyTestHelpers::diag ("bad: $name by rewind next() hi=$hi");
MyTestHelpers::diag ($diff);
MyTestHelpers::diag (ref $seq);
MyTestHelpers::diag ("got len ".scalar(@$got));
MyTestHelpers::diag ("want len ".scalar(@$want));
if ($#$got > 200) { $#$got = 200 }
if ($#$want > 200) { $#$want = 200 }
MyTestHelpers::diag ("got ". join(',', map {defined() ? $_ : 'undef'} @$got));
MyTestHelpers::diag ("want ". join(',', map {defined() ? $_ : 'undef'} @$want));
}
}
{
### by pred() ...
$seq->can('pred')
or next;
if ($seq->characteristic('count')) {
### no pred on characteristic(count) ..
next;
}
if (! $seq->characteristic('increasing')) {
### no pred on not characteristic(increasing) ..
next;
}
if ($seq->characteristic('digits')) {
### no pred on characteristic(digits) ..
next;
}
if ($seq->characteristic('modulus')) {
### no pred on characteristic(modulus) ..
next;
}
if ($seq->characteristic('pn1')) {
### no pred on characteristic(pn1) ..
next;
}
$hi = 0;
foreach my $want (@$want) {
if ($want > $hi) { $hi = $want }
}
if ($hi > 1000) {
$hi = 1000;
$want = [ grep {$_<=$hi} @$want ];
}
_delete_duplicates($want);
#### $want
my @got;
foreach my $value (_min(@$want) .. $hi) {
#### $value
if ($seq->pred($value)) {
push @got, $value;
}
}
my $got = \@got;
my $diff = MyOEIS::diff_nums($got, $want);
if (defined $diff) {
$good = 0;
MyTestHelpers::diag ("bad: $name by pred() hi=$hi");
MyTestHelpers::diag ($diff);
MyTestHelpers::diag (ref $seq);
MyTestHelpers::diag ("got len ".scalar(@$got));
MyTestHelpers::diag ("want len ".scalar(@$want));
if ($#$got > 200) { $#$got = 200 }
if ($#$want > 200) { $#$want = 200 }
MyTestHelpers::diag ("got ". join(',', map {defined() ? $_ : 'undef'} @$got));
MyTestHelpers::diag ("want ". join(',', map {defined() ? $_ : 'undef'} @$want));
}
{
my $data_min = _min(@$want);
my $values_min = $seq->values_min;
if (defined $values_min && $values_min != $data_min) {
$good = 0;
MyTestHelpers::diag ("bad: $name values_min $values_min but data min $data_min");
}
}
{
my $data_max = _max(@$want);
my $values_max = $seq->values_max;
if (defined $values_max && $values_max != $data_max) {
$good = 0;
MyTestHelpers::diag ("bad: $name values_max $values_max not seen in data, only $data_max");
}
}
}
$total_checks++;
}
#------------------------------------------------------------------------------
# extras
# check_class ('A059906', # ZOrderCurve second bit
# 'Math::NumSeq::PlanePathCoord',
# [ planepath => 'CornerReplicate',
# coordinate_type => 'Y' ]);
# exit 0;
#------------------------------------------------------------------------------
# OEIS-Other vs files
MyTestHelpers::diag ("\"Other\" uncatalogued sequences:");
{
system("perl ../ns/tools/make-oeis-catalogue.pl --module=TempOther --other=only") == 0
or die;
require 'lib/Math/NumSeq/OEIS/Catalogue/Plugin/TempOther.pm';
unlink 'lib/Math/NumSeq/OEIS/Catalogue/Plugin/TempOther.pm' or die;
my $aref = Math::NumSeq::OEIS::Catalogue::Plugin::TempOther::info_arrayref();
foreach my $info (@$aref) {
### $info
check_class ($info->{'anum'},
$info->{'class'},
$info->{'parameters'});
}
MyTestHelpers::diag ("");
}
#------------------------------------------------------------------------------
# OEIS-Catalogue generated vs files
MyTestHelpers::diag ("Catalogue sequences:");
{
require Math::NumSeq::OEIS::Catalogue::Plugin::PlanePath;
my $aref = Math::NumSeq::OEIS::Catalogue::Plugin::PlanePath->info_arrayref();
{
require Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick;
my $aref2 = Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick->info_arrayref();
$aref = [ @$aref, @$aref2 ];
}
MyTestHelpers::diag ("total catalogue entries ",scalar(@$aref));
foreach my $info (@$aref) {
### $info
check_class ($info->{'anum'},
$info->{'class'},
$info->{'parameters'});
}
}
MyTestHelpers::diag ("total checks $total_checks");
ok ($good);
exit 0;
Math-PlanePath-113/xt/oeis/SierpinskiArrowhead-oeis.t 0000644 0001750 0001750 00000005771 12136177277 020417 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 14;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::SierpinskiCurve;
use Math::NumSeq::PlanePathTurn;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A189706 - turn sequence odd positions
MyOEIS::compare_values
(anum => 'A189706',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiArrowhead',
turn_type => 'Right');
my @got;
for (my $i = 1; @got < $count; $i+=2) {
push @got, $seq->ith($i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A189707 - (N+1)/2 of positions of odd N left turns
MyOEIS::compare_values
(anum => 'A189707',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiArrowhead',
turn_type => 'Left');
my @got;
for (my $i = 1; @got < $count; $i+=2) {
my $left = $seq->ith($i);
if ($left) {
push @got, ($i+1)/2;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A189708 - (N+1)/2 of positions of odd N right turns
MyOEIS::compare_values
(anum => 'A189708',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiArrowhead',
turn_type => 'Right');
my @got;
for (my $i = 1; @got < $count; $i+=2) {
my $right = $seq->ith($i);
if ($right) {
push @got, ($i+1)/2;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A156595 - turn sequence even positions
MyOEIS::compare_values
(anum => 'A156595',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiArrowhead',
turn_type => 'Right');
my @got;
for (my $i = 2; @got < $count; $i+=2) {
push @got, $seq->ith($i);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DiagonalsAlternating-oeis.t 0000644 0001750 0001750 00000011232 12070671327 020511 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 8;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DiagonalsAlternating;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A056011 -- permutation N at points by Diagonals,direction=up order
MyOEIS::compare_values
(anum => 'A056011',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DiagonalsAlternating->new;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up');
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x, $y) = $diag->n_to_xy ($n);
push @got, $path->xy_to_n ($x,$y);
}
return \@got;
});
# is self-inverse
MyOEIS::compare_values
(anum => 'A056011',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Diagonals->new (direction => 'up');
my $diag = Math::PlanePath::DiagonalsAlternating->new;
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x, $y) = $diag->n_to_xy ($n);
push @got, $path->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A056023 -- permutation N at points by Diagonals,direction=up order
MyOEIS::compare_values
(anum => 'A056023',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DiagonalsAlternating->new;
my $diag = Math::PlanePath::Diagonals->new (direction => 'down');
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x, $y) = $diag->n_to_xy ($n);
push @got, $path->xy_to_n ($x,$y);
}
return \@got;
});
# is self-inverse
MyOEIS::compare_values
(anum => 'A056023',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Diagonals->new (direction => 'down');
my $diag = Math::PlanePath::DiagonalsAlternating->new;
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x, $y) = $diag->n_to_xy ($n);
push @got, $path->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A038722 -- permutation N at transpose Y,X n_start=1
MyOEIS::compare_values
(anum => 'A038722',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DiagonalsAlternating->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A061579 -- permutation N at transpose Y,X
MyOEIS::compare_values
(anum => 'A061579',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DiagonalsAlternating->new (n_start => 0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A131179 -- X axis, extra 0
MyOEIS::compare_values
(anum => 'A131179',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::DiagonalsAlternating->new;
for (my $x = 0; @got < $count; $x++) {
push @got, $path->xy_to_n ($x, 0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A128918 -- Y axis, extra 0
MyOEIS::compare_values
(anum => 'A128918',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::DiagonalsAlternating->new;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n (0, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DiagonalsOctant-oeis.t 0000644 0001750 0001750 00000020425 12154502770 017473 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Carp;
use Math::BigInt;
use Math::PlanePath::DiagonalsOctant;
use Test;
plan tests => 12;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A079826 -- concat of rows numbers in diagonals octant order
# rows numbered alternately left and right
MyOEIS::compare_values
(anum => q{A079826}, # not xreffed
max_count => 10, # various dodginess from a(11)=785753403227
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
require Math::BigInt;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
my $prev_d = 0;
my $str = '';
for (my $n = Math::BigInt->new($diag->n_start); @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
my $d = $x+$y;
if ($d != $prev_d) {
push @got, Math::BigInt->new($str);
$str = '';
$prev_d = $d;
}
if ($y % 2) {
$x = $y-$x;
}
my $rn = $rows->xy_to_n($x,$y);
if ($rn >= 73) { $rn -= 2; }
if ($rn >= 99) { $rn -= 2; }
if ($rn >= 129) { $rn -= 2; }
$str .= $rn;
}
return \@got;
});
# foreach my $y (0 .. 21) {
# foreach my $x (0 .. $y) {
# # if ($x+$y > 11) {
# # print "...";
# # last;
# # }
# my $n = $rows->xy_to_n(($y % 2 ? $y-$x : $x), $y);
# printf "%4d", $n;
# }
# print "\n";
# }
#------------------------------------------------------------------------------
# A014616 -- N in column X=1
MyOEIS::compare_values
(anum => 'A014616',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DiagonalsOctant->new (direction => 'up',
n_start => 0);
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n (1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A079823 -- concat of rows numbers in diagonals octant order
MyOEIS::compare_values
(anum => q{A079823}, # not xreffed
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
my $prev_d = 0;
my $str = '';
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
my $d = $x+$y;
if ($d != $prev_d) {
push @got, $str;
$str = '';
$prev_d = $d;
}
$str .= $rows->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A091018 -- permutation diagonals octant -> rows, 0 based
MyOEIS::compare_values
(anum => 'A091018',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
push @got, $rows->xy_to_n($x,$y) - 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A090894 -- permutation diagonals octant -> rows, 0 based, upwards
MyOEIS::compare_values
(anum => 'A090894',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new(direction=>'up');
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
push @got, $rows->xy_to_n($x,$y) - 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A091995 -- permutation diagonals octant -> rows, 1 based, upwards
MyOEIS::compare_values
(anum => 'A091995',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new(direction=>'up');
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
push @got, $rows->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A056536 -- permutation diagonals octant -> rows
MyOEIS::compare_values
(anum => 'A056536',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
push @got, $rows->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A056537 -- permutation rows -> diagonals octant
MyOEIS::compare_values
(anum => 'A056537',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $rows->n_start; @got < $count; $n++) {
my ($x,$y) = $rows->n_to_xy($n);
push @got, $diag->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A004652 -- N start,end of even diagonals
MyOEIS::compare_values
(anum => 'A004652',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::DiagonalsOctant->new;
for (my $y = 0; @got < $count; $y += 2) {
push @got, $path->xy_to_n (0,$y);
last unless @got < $count;
push @got, $path->xy_to_n ($y/2,$y/2);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002620 -- N end each diagonal, extra initial 0s
MyOEIS::compare_values
(anum => 'A002620',
func => sub {
my ($count) = @_;
my @got = (0,0);
my $path = Math::PlanePath::DiagonalsOctant->new;
for (my $x = 0; @got < $count; $x++) {
push @got, $path->xy_to_n ($x,$x);
last unless @got < $count;
push @got, $path->xy_to_n ($x,$x+1);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A002620',
func => sub {
my ($count) = @_;
my @got = (0,0);
my $path = Math::PlanePath::DiagonalsOctant->new (direction => 'up');
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n (0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A092180 -- primes in rows, traversed by DiagonalOctant
MyOEIS::compare_values
(anum => q{A092180}, # not cross-reffed in docs
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new(direction=>'up');
my $rows = Math::PlanePath::PyramidRows->new(step=>1);
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
push @got, MyOEIS::ith_prime($rows->xy_to_n($x,$y));
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/ImaginaryBase-oeis.t 0000644 0001750 0001750 00000010105 12206030357 017121 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::ImaginaryBase;
use Math::PlanePath::Diagonals;
use Math::PlanePath::Base::Digits
'bit_split_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A057300 -- N at transpose Y,X, radix=2
MyOEIS::compare_values
(anum => 'A057300',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ImaginaryBase->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163327 -- N at transpose Y,X, radix=3
MyOEIS::compare_values
(anum => 'A163327',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ImaginaryBase->new (radix => 3);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A126006 -- N at transpose Y,X, radix=4
MyOEIS::compare_values
(anum => 'A126006',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ImaginaryBase->new (radix => 4);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A217558 -- N at transpose Y,X, radix=16
MyOEIS::compare_values
(anum => 'A217558',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ImaginaryBase->new (radix => 16);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A039724 -- negabinary positives -> index, written in binary
MyOEIS::compare_values
(anum => q{A039724},
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::ZOrderCurve;
my $path = Math::PlanePath::ImaginaryBase->new;
my $zorder = Math::PlanePath::ZOrderCurve->new;
for (my $nega = 0; @got < $count; $nega++) {
my $n = $path->xy_to_n ($nega,0);
$n = delete_odd_bits($n);
push @got, to_binary($n);
}
return \@got;
});
sub delete_odd_bits {
my ($n) = @_;
my @bits = bit_split_lowtohigh($n);
my $bit = 1;
my $ret = 0;
while (@bits) {
if (shift @bits) {
$ret |= $bit;
}
shift @bits;
$bit <<= 1;
}
return $ret;
}
# or by string ...
# if (length($str) & 1) { $str = "0$str" }
# $str =~ s/.(.)/$1/g;
sub to_binary {
my ($n) = @_;
return ($n < 0 ? '-' : '') . sprintf('%b', abs($n));
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DiagonalRationals-oeis.t 0000644 0001750 0001750 00000010261 12136177302 020010 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 5;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DiagonalRationals;
my $diagrat = Math::PlanePath::DiagonalRationals->new;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A038567 -- X+Y except no 0/1 in path
MyOEIS::compare_values
(anum => 'A038567',
max_count => 10000,
func => sub {
my ($count) = @_;
my @got = (1);
for (my $n = $diagrat->n_start; @got < $count; $n++) {
my ($x, $y) = $diagrat->n_to_xy ($n);
push @got, $x+$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054430 -- N at transpose Y,X
MyOEIS::compare_values
(anum => 'A054430',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $diagrat->n_start; @got < $count; $n++) {
my ($x, $y) = $diagrat->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $diagrat->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054431 - by anti-diagonals 1 if coprime, 0 if not
MyOEIS::compare_values
(anum => 'A054431',
func => sub {
my ($count) = @_;
my @got;
my $prev_n = $diagrat->n_start - 1;
OUTER: for (my $y = 1; ; $y ++) {
foreach my $x (1 .. $y-1) {
my $n = $diagrat->xy_to_n($x,$y-$x);
if (defined $n) {
push @got, 1;
if ($n != $prev_n + 1) {
die "oops, not n+1";
}
$prev_n = $n;
} else {
push @got, 0;
}
last OUTER if @got >= $count;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A054424 - permutation diagonal N -> SB N
# A054426 - inverse SB N -> Cantor N
MyOEIS::compare_values
(anum => 'A054424',
func => sub {
my ($count) = @_;
require Math::PlanePath::RationalsTree;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got;
foreach my $n (1 .. $count) {
my ($x,$y) = $diagrat->n_to_xy ($n);
push @got, $sb->xy_to_n($x,$y);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A054426',
func => sub {
my ($count) = @_;
require Math::PlanePath::RationalsTree;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got;
foreach my $n (1 .. $count) {
my ($x,$y) = $sb->n_to_xy ($n);
push @got, $diagrat->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054425 - A054424 mapping expanded out to 0s at common-factor X,Y
MyOEIS::compare_values
(anum => 'A054425',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
require Math::PlanePath::RationalsTree;
my $diag = Math::PlanePath::Diagonals->new (x_start=>1, y_start=>1);
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got;
for (my $n = $diag->n_start; @got < $count; $n++) {
my ($x,$y) = $diag->n_to_xy($n);
### frac: "$x/$y"
my $cn = $diagrat->xy_to_n ($x,$y);
if (defined $cn) {
push @got, $sb->xy_to_n($x,$y);
} else {
push @got, 0;
}
}
return \@got;
});
exit 0;
Math-PlanePath-113/xt/oeis/TheodorusSpiral-oeis.t 0000644 0001750 0001750 00000006211 12136177277 017557 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 8;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::TheodorusSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A172164 -- differences of loop lengths
MyOEIS::compare_values
(anum => 'A172164',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TheodorusSpiral->new;
my $n = $path->n_start + 1;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
my $prev_n = 1;
my $prev_looplen = 0;
my $first = 1;
for ($n++; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($y > 0 && $prev_y < 0) {
my $looplen = $n-$prev_n;
if ($first) {
$first = 0;
} else {
push @got, $looplen - $prev_looplen;
}
$prev_n = $n;
$prev_looplen = $looplen;
}
($prev_x, $prev_y) = ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A137515 -- right triangles in n turns
# 16, 53, 109, 185, 280, 395, 531, 685, 860, 1054, 1268, 1502, 1756,
MyOEIS::compare_values
(anum => 'A137515',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TheodorusSpiral->new;
my $n = $path->n_start + 1;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
for ($n++; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($y > 0 && $prev_y < 0) {
push @got, $n-2;
}
($prev_x, $prev_y) = ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A072895 -- points to complete n revolutions
# 17, 54, 110, 186, 281, 396, 532, 686, 861, 1055, 1269, 1503, 1757,
MyOEIS::compare_values
(anum => 'A072895',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TheodorusSpiral->new;
my $n = $path->n_start + 2;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
for ($n++; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($y >= 0 && $prev_y <= 0) {
push @got, $n-1;
}
($prev_x, $prev_y) = ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CellularRule54-oeis.t 0000644 0001750 0001750 00000004040 12136177303 017160 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Devel::Comments '###';
use Math::PlanePath::CellularRule54;
my $path = Math::PlanePath::CellularRule54->new;
#------------------------------------------------------------------------------
# A118109 - 0/1 by rows
MyOEIS::compare_values
(anum => 'A118109',
func => sub {
my ($count) = @_;
my @got;
my $x = 0;
my $y = 0;
foreach my $n (1 .. $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A118108 - rows as bignum bits
MyOEIS::compare_values
(anum => 'A118108',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $y = 0;
foreach my $n (1 .. $count) {
my $b = 0;
foreach my $i (0 .. 2*$y+1) {
if ($path->xy_to_n ($y-$i, $y)) {
$b += Math::BigInt->new(2) ** $i;
}
}
push @got, "$b";
$y++;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/RationalsTree-oeis.t 0000644 0001750 0001750 00000072020 12224507344 017173 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# cf A152975/A152976 redundant Stern-Brocot
# inserting mediants to make ternary tree
use 5.004;
use strict;
use Test;
plan tests => 49;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::RationalsTree;
# uncomment this to run the ### lines
#use Smart::Comments '###';
sub gcd {
my ($x, $y) = @_;
#### _gcd(): "$x,$y"
if ($y > $x) {
$y %= $x;
}
for (;;) {
if ($y <= 1) {
return ($y == 0 ? $x : 1);
}
($x,$y) = ($y, $x % $y);
}
}
#------------------------------------------------------------------------------
# A000975 -- 010101 without consecutive equal bits, Bird tree X=1 column
MyOEIS::compare_values
(anum => 'A000975',
max_count => 100,
name => "Bird column X=1",
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my @got = (0); # extra initial 0 in A000975
require Math::BigInt;
for (my $y = Math::BigInt->new(1); @got < $count; $y++) {
push @got, $path->xy_to_n (1, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A061547 -- 010101 without consecutive equal bits, Drib tree X=1 column
# Y/1 in Drib, extra initial 0 in A061547
MyOEIS::compare_values
(anum => 'A061547',
max_count => 100,
name => "Drib column X=1",
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
my @got = (0); # extra initial 0 in A061547
for (my $y = Math::BigInt->new(1); @got < $count; $y++) {
push @got, $path->xy_to_n (1, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A086893 -- Drib tree Y=1 row
MyOEIS::compare_values
(anum => 'A086893',
max_count => 100,
name => "Drib row Y=1",
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
my @got;
require Math::BigInt;
for (my $x = Math::BigInt->new(1); @got < $count; $x++) {
push @got, $path->xy_to_n ($x, 1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A229742 -- HCS numerators
# 0, 1, 2, 1, 3, 3, 1, 2, 4, 5, 4, 5, 1, 2, 3, 3, 5, 7, 7, 8, 5, 7, 7, 8,
MyOEIS::compare_values
(anum => 'A229742',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my @got = (0); # extra initial 0/1
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A071766 -- HCS denominators
# 1, 1, 1, 2, 1, ...
MyOEIS::compare_values
(anum => 'A071766',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my @got = (1); # extra initial 1/1
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A071585 -- HCS num+den
# 1, 2, 3, 3, 4, ...
MyOEIS::compare_values
(anum => 'A071585',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my @got = (1); # extra initial 1/1 then Rat+1
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x+$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A154435 -- permutation HCS->Bird, lamplighter
MyOEIS::compare_values
(anum => 'A154435',
func => sub {
my ($count) = @_;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $bird = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my @got = (0); # initial 0
for (my $n = $hcs->n_start; @got < $count; $n++) {
my ($x, $y) = $hcs->n_to_xy($n);
push @got, $bird->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A154436 -- permutation Bird->HCS, lamplighter inverse
MyOEIS::compare_values
(anum => 'A154436',
func => sub {
my ($count) = @_;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $bird = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my @got = (0); # initial 0
for (my $n = $bird->n_start; @got < $count; $n++) {
my ($x, $y) = $bird->n_to_xy($n);
push @got, $hcs->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A059893 -- bit-reversal permutation
# CW<->SB
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my $cw = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got;
for (my $n = $cw->n_start; @got < $count; $n++) {
my ($x, $y) = $cw->n_to_xy($n);
push @got, $sb->xy_to_n($x,$y);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my @got;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my $cw = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
for (my $n = $sb->n_start; @got < $count; $n++) {
my ($x, $y) = $sb->n_to_xy($n);
push @got, $cw->xy_to_n($x,$y);
}
return \@got;
});
# Drib<->Bird
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my $bird = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my $drib = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
my @got;
for (my $n = $drib->n_start; @got < $count; $n++) {
my ($x, $y) = $drib->n_to_xy($n);
push @got, $bird->xy_to_n($x,$y);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my @got;
my $bird = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my $drib = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
for (my $n = $bird->n_start; @got < $count; $n++) {
my ($x, $y) = $bird->n_to_xy($n);
push @got, $drib->xy_to_n($x,$y);
}
return \@got;
});
# AYT<->HCS
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my @got;
for (my $n = $ayt->n_start; @got < $count; $n++) {
my ($x, $y) = $ayt->n_to_xy($n);
push @got, $hcs->xy_to_n($x,$y);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A059893',
func => sub {
my ($count) = @_;
my @got;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
for (my $n = $hcs->n_start; @got < $count; $n++) {
my ($x, $y) = $hcs->n_to_xy($n);
push @got, $ayt->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A047270 -- 3or5 mod 6, is CW positions of X>Y not both odd
MyOEIS::compare_values
(anum => 'A047270',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if (xy_is_pythagorean($x,$y)) {
push @got, $n;
}
}
return \@got;
});
sub xy_is_pythagorean {
my ($x,$y) = @_;
return ($x>$y && ($x%2)!=($y%2));
}
#------------------------------------------------------------------------------
# A057431 -- SB num then den, initial 0/1, 1/0 too
MyOEIS::compare_values
(anum => 'A057431',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got = (0,1, 1,0);
for (my $n = $path->n_start; ; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
last if @got >= $count;
push @got, $x;
last if @got >= $count;
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A104106 AYT 2*N Left -- not quite
# a(1) = 1
# if A(k) = sequence of first 2^k -1 terms, then
# A(k+1) = A(k), 1, A(k) if a(k) = 0
# A(k+1) = A(k), 0, A(k) if a(k) = 1
# A104106 ,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,
# sub A104106_func {
# my ($n) = @_;
# my @array;
# $array[1] = 1;
# my $k = 1; # initially 2^1-1 = 2-1 = 1 term
# while ($#array < $n) {
# my $last = $#array;
# push @array,
# $array[$k] ? 0 : 1,
# @array[1 .. $last]; # array slice
# # print "\n$k array ",join(',',@array[1..$#array]),"\n";
# $k++;
# }
# return $array[$n];
# }
# print "A104106_func: ";
# foreach my $i (1 .. 20) {
# print A104106_func($i),",";
# }
# print "\n";
#
# {
# require Math::NumSeq::PlanePathTurn;
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'RationalsTree,tree_type=AYT',
# turn_type => 'Left');
# print "seq: ";
# foreach my $i (1 .. 20) {
# print $seq->ith(2*$i),",";
# }
# print "\n";
#
# foreach my $k (1 .. 100) {
# my $i = 2*$k;
# my $s = $seq->ith($i);
# my $a = A104106_func($k+10);
# my $diff = ($s != $a ? ' ***' : '');
# print "$i $s $a$diff\n";
# }
# }
#------------------------------------------------------------------------------
# HCS num=A071585 den=A071766
# A010060 is 1=right or straight, 0=left
# straight only at i=2 1,1, 2,1, 3,1
{
require Math::NumSeq::OEIS::File;
require Math::NumberCruncher;
require Math::BaseCnv;
my $num = Math::NumSeq::OEIS::File->new(anum=>'A071585'); # OFFSET=0
my $den = Math::NumSeq::OEIS::File->new(anum=>'A071766'); # OFFSET=0
my $seq_A010060 = Math::NumSeq::OEIS->new(anum=>'A010060');
(undef, my $n1) = $num->next;
(undef, my $n2) = $num->next;
(undef, my $d1) = $den->next;
(undef, my $d2) = $den->next;
# $n1 += $d1; $n2 += $d2;
my $count = 0;
for (;;) {
(my $i, my $n3) = $num->next or last;
(undef, my $d3) = $den->next;
# Clockwise() positive for clockwise=right, negative for anti=left
my $turn = Math::NumberCruncher::Clockwise($n1,$d1, $n2,$d2, $n3,$d3);
if ($turn > 0) { $turn = 1; } # 1=right
elsif ($turn < 0) { $turn = 0; } # 0=left, 1=right
else { $turn = 1;
MyTestHelpers::diag ("straight i=$i $n1,$d1, $n2,$d2, $n3,$d3");
}
# print "$turn,"; next;
my $turn_by_A010060 = $seq_A010060->ith($i); # n of third of triplet
if ($turn != $turn_by_A010060) {
die "oops, wrong at i=$i";
}
# if (is_pow2($i)) { print "\n"; }
# my $i2 = Math::BaseCnv::cnv($i,10,2);
# printf "%2s %5s %2s,%-2s %d %d\n", $i,$i2, $n3,$d3, $turn, $turn_by_A010060;
$n1 = $n2; $n2 = $n3;
$d1 = $d2; $d2 = $d3;
$count++;
}
MyTestHelpers::diag ("HCS OEIS vs A010060 count $count");
ok (1,1);
}
#------------------------------------------------------------------------------
# A010060 -- HCS turn right is (-1)^count1bits of N+1, Thue-Morse +/-1
# OFFSET=0, extra initial n=0,1,2 then n=3 is N=2
MyOEIS::compare_values
(anum => 'A010060',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'RationalsTree,tree_type=HCS',
turn_type => 'Right');
my @got = (0,1,1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
# A106400 -- HCS left +/-1 thue-morse parity, OFFSET=0
MyOEIS::compare_values
(anum => 'A106400',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'RationalsTree,tree_type=HCS',
turn_type => 'Left');
my @got = (1,-1,-1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, 2*$value-1;
}
return \@got;
});
# +/-1 OFFSET=1, extra initial n=1,n=2 then n=3 is N=2
MyOEIS::compare_values
(anum => 'A108784',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'RationalsTree,tree_type=HCS',
turn_type => 'Right');
my @got = (1,1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, 2*$value-1;
}
return \@got;
});
# A010059 -- HCS Left, count0bits mod 2 of N+1
MyOEIS::compare_values
(anum => 'A010059',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'RationalsTree,tree_type=HCS',
turn_type => 'Left');
my @got = (1,0,0);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A070990 -- CW Y-X is Stern diatomic first diffs, starting from N=2
MyOEIS::compare_values
(anum => 'A070990',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y - $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A007814 -- CW floor(X/Y) is count trailing 1-bits
# A007814 count trailing 0-bits is same, at N+1
MyOEIS::compare_values
(anum => 'A007814',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, int($x/$y);
}
return \@got;
});
# A007814 -- AYT floor(X/Y) is count trailing 0-bits,
# except at N=2^k where 1 fewer
MyOEIS::compare_values
(anum => 'A007814',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my $i = int($x/$y);
if (is_pow2($n)) {
$i--;
}
push @got, $i;
}
return \@got;
});
sub is_pow2 {
my ($n) = @_;
while ($n > 1) {
if ($n & 1) {
return 0;
}
$n >>= 1;
}
return ($n == 1);
}
#------------------------------------------------------------------------------
# A004442 -- AYT N at transpose Y,X, flip low bit
MyOEIS::compare_values
(anum => 'A004442',
func => sub {
my ($count) = @_;
my @got = (1,0);
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
for (my $n = 2; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A063946 -- HCS N at transpose Y,X, flip second lowest bit
MyOEIS::compare_values
(anum => 'A063946',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054429 -- N at transpose Y,X, row right to left
foreach my $tree_type ('SB','CW','Bird','Drib') {
MyOEIS::compare_values
(anum => 'A054429',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::RationalsTree->new (tree_type => $tree_type);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A072030 - subtraction steps for gcd(x,y) by triangle rows
MyOEIS::compare_values
(anum => q{A072030},
func => sub {
my ($count) = @_;
require Math::PlanePath::PyramidRows;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my $triangle = Math::PlanePath::PyramidRows->new (step => 1);
my @got;
for (my $n = $triangle->n_start; @got < $count; $n++) {
my ($x,$y) = $triangle->n_to_xy ($n);
next unless $x < $y; # so skipping GCD(x,x)==x taking 0 steps
$x++;
$y++;
my $gcd = gcd($x,$y);
$x /= $gcd;
$y /= $gcd;
my $n = $path->xy_to_n($x,$y);
die unless defined $n;
my $depth = $path->tree_n_to_depth($n);
push @got, $depth;
}
return \@got;
});
#------------------------------------------------------------------------------
# A072031 - row sums of A072030 subtraction steps for gcd(x,y) by rows
MyOEIS::compare_values
(anum => q{A072031},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'SB');
my @got;
for (my $y = 2; @got < $count; $y++) {
my $total = -1; # gcd(1,Y) taking 0 steps, maybe
for (my $x = 1; $x < $y; $x++) {
my $gcd = gcd($x,$y);
my $n = $path->xy_to_n($x/$gcd,$y/$gcd);
die unless defined $n;
$total += $path->tree_n_to_depth($n);
}
push @got, $total+1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003188 -- permutation SB->HCS, Gray code shift+xor
MyOEIS::compare_values
(anum => 'A003188',
func => sub {
my ($count) = @_;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got = (0); # initial 0
for (my $n = $sb->n_start; @got < $count; $n++) {
my ($x, $y) = $sb->n_to_xy($n);
push @got, $hcs->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A006068 -- permutation HCS->SB, Gray code inverse
MyOEIS::compare_values
(anum => 'A006068',
func => sub {
my ($count) = @_;
my $hcs = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got = (0); # initial 0
for (my $n = $hcs->n_start; @got < $count; $n++) {
my ($x, $y) = $hcs->n_to_xy($n);
push @got, $sb->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# Stern diatomic A002487
# A002487 -- L denominators, L doesn't have initial 0,1 of diatomic
MyOEIS::compare_values
(anum => 'A002487',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'L');
my @got = (0,1);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
# A002487 -- CW numerators, is Stern diatomic
MyOEIS::compare_values
(anum => 'A002487',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
# A002487 -- CW denominators are Stern diatomic
MyOEIS::compare_values
(anum => 'A002487',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got = (0,1); # extra initial
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A153153 -- permutation CW->AYT
MyOEIS::compare_values
(anum => 'A153153',
func => sub {
my ($count) = @_;
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my $cw = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got = (0); # initial 0
for (my $n = $cw->n_start; @got < $count; $n++) {
my ($x, $y) = $cw->n_to_xy($n);
push @got, $ayt->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A153154 -- permutation AYT->CW
MyOEIS::compare_values
(anum => 'A153154',
func => sub {
my ($count) = @_;
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my $cw = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got = (0); # initial 0
for (my $n = $ayt->n_start; @got < $count; $n++) {
my ($x, $y) = $ayt->n_to_xy($n);
push @got, $cw->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A154437 -- permutation AYT->Drib
MyOEIS::compare_values
(anum => 'A154437',
func => sub {
my ($count) = @_;
my $drib = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my @got = (0); # initial 0
for (my $n = $ayt->n_start; @got < $count; $n++) {
my ($x, $y) = $ayt->n_to_xy($n);
push @got, $drib->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A154438 -- permutation Drib->AYT
MyOEIS::compare_values
(anum => 'A154438',
func => sub {
my ($count) = @_;
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my $drib = Math::PlanePath::RationalsTree->new (tree_type => 'Drib');
my @got = (0); # initial 0
for (my $n = $drib->n_start; @got < $count; $n++) {
my ($x, $y) = $drib->n_to_xy($n);
push @got, $ayt->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A061547 -- pos of frac F(n)/F(n+1) in Stern diatomic, is CW N
# F(n)/F(n+1) in CW, extra initial 0
MyOEIS::compare_values
(anum => 'A061547',
max_count => 100,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got = (0); # extra initial 0 in seq A061547
require Math::BigInt;
my $f1 = Math::BigInt->new(1);
my $f0 = Math::BigInt->new(1);
while (@got < $count) {
push @got, $path->xy_to_n ($f0, $f1);
($f1,$f0) = ($f1+$f0,$f1);
}
return \@got;
});
# #------------------------------------------------------------------------------
# # A113881
# # different as n=49
#
# {
# my $anum = 'A113881';
# my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
# my $skip;
# my @got;
# my $diff;
# if ($bvalues) {
# require Math::PlanePath::Diagonals;
# my $path = Math::PlanePath::RationalsTree->new(tree_type => 'SB');
# my $diag = Math::PlanePath::Diagonals->new;
# for (my $n = $diag->n_start; @got < $count; $n++) {
# my ($x,$y) = $diag->n_to_xy ($n);
# $x++;
# $y++;
# my $gcd = gcd($x,$y);
# $x /= $gcd;
# $y /= $gcd;
# my $n = $path->xy_to_n($x,$y);
# my $nbits = sprintf '%b', $n;
# push @got, length($nbits);
# }
# $diff = diff_nums(\@got, $bvalues);
# if ($diff) {
# MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..30]));
# MyTestHelpers::diag ("got: ",join(',',@got[0..30]));
# }
# }
# skip (! $bvalues,
# $diff, undef,
# "$anum");
# }
#------------------------------------------------------------------------------
# A088696 -- length of continued fraction of SB fractions
if (! eval { require Math::ContinuedFraction; 1 }) {
skip ("Math::ContinuedFraction not available",
0,0);
} else {
MyOEIS::compare_values
(anum => 'A088696',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'SB');
OUTER: for (my $k = 1; @got < $count; $k++) {
foreach my $n (2**$k .. 2**$k + 2**($k-1) - 1) {
my ($x,$y) = $path->n_to_xy ($n);
my $cf = Math::ContinuedFraction->from_ratio($x,$y);
my $cfaref = $cf->to_array;
my $cflen = scalar(@$cfaref);
push @got, $cflen-1; # -1 to skip initial 0 term in $cf
### cf: "n=$n xy=$x/$y cflen=$cflen ".$cf->to_ascii
last OUTER if @got >= $count;
}
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A086893 -- pos of frac F(n+1)/F(n) in Stern diatomic, is CW N
MyOEIS::compare_values
(anum => 'A086893',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my @got;
my $f1 = 1;
my $f0 = 1;
while (@got < $count) {
push @got, $path->xy_to_n ($f1, $f0);
($f1,$f0) = ($f1+$f0,$f1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A007305 -- SB numerators
MyOEIS::compare_values
(anum => 'A007305',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got = (0,1); # extra initial
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A047679 -- SB denominators
MyOEIS::compare_values
(anum => 'A047679',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A007306 -- SB num+den
MyOEIS::compare_values
(anum => 'A007306',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my @got = (1,1); # extra initial
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x+$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A162911 -- Drib tree numerators = Bird tree reverse N
MyOEIS::compare_values
(anum => q{A162911},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $path->n_to_xy (bit_reverse ($n));
push @got, $x;
}
return \@got;
});
sub bit_reverse {
my ($n) = @_;
my $rev = 1;
while ($n > 1) {
$rev = 2*$rev + ($n % 2);
$n = int($n/2);
}
return $rev;
}
#------------------------------------------------------------------------------
# A162912 -- Drib tree denominators = Bird tree reverse
MyOEIS::compare_values
(anum => q{A162912},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'Bird');
my @got;
foreach my $n (1 .. $count) {
my ($x, $y) = $path->n_to_xy (bit_reverse ($n));
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CfracDigits-oeis.t 0000644 0001750 0001750 00000006265 12136177302 016610 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 5;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CfracDigits;
use Math::PlanePath::Base::Digits
'digit_join_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A071766 -- radix=1 X numerators, same as HCS denominators
# except at OFFSET=0 extra initial 1 from 0/1
MyOEIS::compare_values
(anum => 'A071766',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CfracDigits->new (radix => 1);
my @got = (1);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A032924 - N in X=1 column, ternary no digit 0
MyOEIS::compare_values
(anum => 'A032924',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CfracDigits->new;
my @got;
for (my $y = 3; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A023705 - N in X=1 column, base4 no digit 0
MyOEIS::compare_values
(anum => 'A023705',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CfracDigits->new (radix => 3);
my @got;
for (my $y = 3; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A023721 - N in X=1 column, base5 no digit 0
MyOEIS::compare_values
(anum => 'A023721',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CfracDigits->new (radix => 4);
my @got;
for (my $y = 3; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A052382 - N in X=1 column, base5 no digit 0
MyOEIS::compare_values
(anum => 'A052382',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CfracDigits->new (radix => 9);
my @got;
for (my $y = 3; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/OctagramSpiral-oeis.t 0000644 0001750 0001750 00000002672 12164405074 017335 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 7;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::OctagramSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A125201 -- N on X axis, from X=1 onwards, 18-gonals + 1
MyOEIS::compare_values
(anum => 'A125201',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::OctagramSpiral->new;
my @got;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,0);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/SquareSpiral-oeis.t 0000644 0001750 0001750 00000116426 12164412270 017037 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A168022 Non-composite numbers in the eastern ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A168023 Non-composite numbers in the northern ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A168024 Non-composite numbers in the northwestern ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A168025 Non-composite numbers in the western ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A168026 Non-composite numbers in the southwestern ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A168027 Non-composite numbers in the southern ray of the Ulam spiral as oriented on the March 1964 cover of Scientific American.
# A217014 Permutation of natural numbers arising from applying the walk of a square spiral (e.g. A214526) to the data of triangular horizontal-last spiral (defined in A214226).
# A217015 Permutation of natural numbers arising from applying the walk of a square spiral (e.g. A214526) to the data of rotated-square spiral (defined in A215468).
# A053823 Product of primes in n-th shell of prime spiral.
# A053997 Sum of primes in n-th shell of prime spiral.
# A053998 Smallest prime in n-th shell of prime spiral.
# A059924 Write the numbers from 1 to n^2 in a spiraling square; a(n) is the total of the sums of the two diagonals.
# A113688 Isolated semiprimes in the semiprime spiral.
# A113689 Number of semiprimes in clumps of size >1 through n^2 in the semiprime spiral.
# A114254 Sum of all terms on the two principal diagonals of a 2n+1 X 2n+1 square spiral.
use 5.004;
use strict;
use Test;
plan tests => 58;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min','max','sum';
use Math::PlanePath::SquareSpiral;
# uncomment this to run the ### lines
# use Smart::Comments '###';
my $path = Math::PlanePath::SquareSpiral->new;
# return 1,2,3,4
sub path_n_dir4_1 {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
return dxdy_to_dir4_1 ($next_x - $x,
$next_y - $y);
}
# return 1,2,3,4, with Y reckoned increasing upwards
sub dxdy_to_dir4_1 {
my ($dx, $dy) = @_;
if ($dx > 0) { return 1; } # east
if ($dx < 0) { return 3; } # west
if ($dy > 0) { return 2; } # north
if ($dy < 0) { return 4; } # south
}
#------------------------------------------------------------------------------
# A027709 -- boundary length
{
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_n_to_dboundary {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my $dboundary = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dboundary -= 2*(defined $an && $an < $n);
}
return $dboundary;
}
}
MyOEIS::compare_values
(anum => 'A027709',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, $boundary;
$boundary += path_n_to_dboundary($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A078633 -- grid sticks
{
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_n_to_dsticks {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my $dsticks = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dsticks -= (defined $an && $an < $n);
}
return $dsticks;
}
}
MyOEIS::compare_values
(anum => 'A078633',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
$boundary += path_n_to_dsticks($path,$n);
push @got, $boundary;
}
return \@got;
});
#------------------------------------------------------------------------------
# A094768 -- cumulative spiro-fibonacci total of 4 neighbours
{
my @surround4_dx = (1, 0, -1, 0);
my @surround4_dy = (0, 1, 0, -1);
MyOEIS::compare_values
(anum => q{A094768},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
require Math::BigInt;
my $total = Math::BigInt->new(1);
my @got = ($total);
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n-1);
foreach my $i (0 .. $#surround4_dx) {
my $sn = $path->xy_to_n ($x+$surround4_dx[$i], $y+$surround4_dy[$i]);
if ($sn < $n) {
$total += $got[$sn];
}
}
$got[$n] = $total;
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A094767 -- cumulative spiro-fibonacci total of 8 neighbours
my @surround8_dx = (1, 1, 0, -1, -1, -1, 0, 1);
my @surround8_dy = (0, 1, 1, 1, 0, -1, -1, -1);
MyOEIS::compare_values
(anum => q{A094767},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
require Math::BigInt;
my $total = Math::BigInt->new(1);
my @got = ($total);
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n-1);
foreach my $i (0 .. $#surround8_dx) {
my $sn = $path->xy_to_n ($x+$surround8_dx[$i], $y+$surround8_dy[$i]);
if ($sn < $n) {
$total += $got[$sn];
}
}
$got[$n] = $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A094769 -- cumulative spiro-fibonacci total of 8 neighbours starting 0,1
MyOEIS::compare_values
(anum => q{A094769},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
require Math::BigInt;
my $total = Math::BigInt->new(1);
my @got = (0, $total);
for (my $n = $path->n_start + 2; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n-1);
foreach my $i (0 .. $#surround8_dx) {
my $sn = $path->xy_to_n ($x+$surround8_dx[$i], $y+$surround8_dy[$i]);
if ($sn < $n) {
$total += $got[$sn];
}
}
$got[$n] = $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A136626 -- count surrounding primes
MyOEIS::compare_values
(anum => q{A136626},
fixup => sub {
my ($bvalues) = @_;
$bvalues->[31] = 3; # DODGY-DATA: 3 primes 13,31,59 surrounding 32
},
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ((!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y-1)))
);
}
return \@got;
});
# A136627 -- count self and surrounding primes
MyOEIS::compare_values
(anum => q{A136627},
fixup => sub {
my ($bvalues) = @_;
$bvalues->[31] = 3; # DODGY-DATA: 3 primes 13,31,59 surrounding 32
},
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, (Math::Prime::XS::is_prime($n)
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y-1)))
);
}
return \@got;
});
#------------------------------------------------------------------------------
# A078784 -- primes on any axis positive or negative
MyOEIS::compare_values
(anum => 'A078784',
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
if ($x == 0 || $y == 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A090925 -- permutation rotate +90
MyOEIS::compare_values
(anum => 'A090925',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x,$y) = (-$y,$x); # rotate +90
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A090928 -- permutation rotate +180
MyOEIS::compare_values
(anum => 'A090928',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x,$y) = (-$x,-$y); # rotate +180
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A090929 -- permutation rotate +270
MyOEIS::compare_values
(anum => 'A090929',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x,$y) = ($y,-$x); # rotate -90
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A090861 -- permutation rotate +180, opp direction
MyOEIS::compare_values
(anum => 'A090861',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
$y = -$y; # opp direction
($x,$y) = (-$x,-$y); # rotate 180
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A090915 -- permutation rotate +270, opp direction
MyOEIS::compare_values
(anum => 'A090915',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
$y = -$y; # opp direction
($x,$y) = ($y,-$x); # rotate -90
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A090930 -- permutation opp direction
MyOEIS::compare_values
(anum => 'A090930',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
$y = -$y; # opp direction
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
# A185413 -- rotate 180, offset X+1,Y
MyOEIS::compare_values
(anum => 'A185413',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
$x = 1 - $x;
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A078765 -- primes at integer radix sqrt(x^2+y^2), and not on axis
MyOEIS::compare_values
(anum => 'A078765',
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
if ($x != 0 && $y != 0 && is_perfect_square($x*$x+$y*$y)) {
push @got, $n;
}
}
return \@got;
});
sub is_perfect_square {
my ($n) = @_;
my $sqrt = int(sqrt($n));
return ($sqrt*$sqrt == $n);
}
#------------------------------------------------------------------------------
# A200975 -- all four diagonals
MyOEIS::compare_values
(anum => 'A200975',
func => sub {
my ($count) = @_;
my @got = (1);
for (my $i = 1; @got < $count; $i++) {
push @got, $path->xy_to_n($i,$i);
last unless @got < $count;
push @got, $path->xy_to_n(-$i,$i);
last unless @got < $count;
push @got, $path->xy_to_n(-$i,-$i);
last unless @got < $count;
push @got, $path->xy_to_n($i,-$i);
last unless @got < $count;
}
return \@got;
});
# #------------------------------------------------------------------------------
# # A195060 -- N on axis or diagonal ???
# # vertices generalized pentagonal 0,1,2,5,7,12,15,22,...
# # union A001318, A032528, A045943
#
# MyOEIS::compare_values
# (anum => 'A195060',
# func => sub {
# my ($count) = @_;
# my @got = (0);
# for (my $n = $path->n_start; @got < $count; $n++) {
# my ($x,$y) = $path->n_to_xy ($n);
# if ($x == $y || $x == -$y || $x == 0 || $y == 0) {
# push @got, $n;
# }
# }
# return \@got;
# });
# #------------------------------------------------------------------------------
# # A137932 -- count points not on diagonals up to nxn
#
# MyOEIS::compare_values
# (anum => 'A137932',
# max_value => 1000,
# func => sub {
# my ($count) = @_;
# my @got;
# for (my $k = 0; @got < $count; $k++) {
# my $num = 0;
# my ($cx,$cy) = $path->n_to_xy ($k*$k);
# foreach my $n (1 .. $k*$k) {
# my ($x,$y) = $path->n_to_xy ($n);
# $num += (abs($x) != abs($y));
# }
# push @got, $num;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A113688 -- isolated semi-primes
MyOEIS::compare_values
(anum => 'A113688',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AlmostPrimes;
my $seq = Math::NumSeq::AlmostPrimes->new;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless $seq->pred($n);
my ($x,$y) = $path->n_to_xy ($n);
if (! $seq->pred ($path->xy_to_n($x+1,$y))
&& ! $seq->pred ($path->xy_to_n($x-1,$y))
&& ! $seq->pred ($path->xy_to_n($x,$y+1))
&& ! $seq->pred ($path->xy_to_n($x,$y-1))
&& ! $seq->pred ($path->xy_to_n($x+1,$y+1))
&& ! $seq->pred ($path->xy_to_n($x-1,$y-1))
&& ! $seq->pred ($path->xy_to_n($x-1,$y+1))
&& ! $seq->pred ($path->xy_to_n($x+1,$y-1))
) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A215470 -- primes with >=4 prime neighbours in 8 surround
MyOEIS::compare_values
(anum => 'A215470',
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
my $num = ((!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y-1)))
);
if ($num >= 4) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A033638 -- N positions of the turns
MyOEIS::compare_values
(anum => 'A033638',
max_value => 100_000,
func => sub {
my ($count) = @_;
my @got;
push @got, 1,1;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'SquareSpiral',
turn_type => 'LSR');
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value != 0) {
push @got, $i;
}
}
return \@got;
});
# A172979 -- N positions of the turns which are also primes
MyOEIS::compare_values
(anum => 'A172979',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::PlanePathTurn;
require Math::Prime::XS;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'SquareSpiral',
turn_type => 'LSR');
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value != 0 && Math::Prime::XS::is_prime($i)) {
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A137930 sum leading and anti diagonal of nxn square
MyOEIS::compare_values
(anum => q{A137930},
func => sub {
my ($count) = @_;
my @got;
for (my $k = 0; @got < $count; $k++) {
push @got, diagonals_total($path,$k);
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A137931}, # 2n x 2n
func => sub {
my ($count) = @_;
my @got;
for (my $k = 0; @got < $count; $k+=2) {
push @got, diagonals_total($path,$k);
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A114254}, # 2n+1 x 2n+1
func => sub {
my ($count) = @_;
my @got;
for (my $k = 1; @got < $count; $k+=2) {
push @got, diagonals_total($path,$k);
}
return \@got;
});
sub diagonals_total {
my ($path, $k) = @_;
### diagonals_total(): $k
if ($k == 0) {
return 0;
}
my ($x,$y) = $path->n_to_xy ($k*$k); # corner
my $dx = ($x > 0 ? -1 : 1);
my $dy = ($y > 0 ? -1 : 1);
### corner: "$x,$y dx=$dx,dy=$dy"
my %n;
foreach my $i (0 .. $k-1) {
my $n = $path->xy_to_n($x,$y);
$n{$n} = 1;
$x += $dx;
$y += $dy;
}
$x -= $k*$dx;
$dy = -$dy;
$y += $dy;
### opposite: "$x,$y dx=$dx,dy=$dy"
foreach my $i (0 .. $k-1) {
my $n = $path->xy_to_n($x,$y);
$n{$n} = 1;
$x += $dx;
$y += $dy;
}
### n values: keys %n
return sum(keys %n);
}
#------------------------------------------------------------------------------
# A059428 -- Prime[N] for N=corner
MyOEIS::compare_values
(anum => q{A059428},
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'LSR');
my @got = (2);
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value) {
push @got, MyOEIS::ith_prime($i); # i=2 as first turn giving prime=3
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A123663 -- count total shared edges
MyOEIS::compare_values
(anum => q{A123663},
func => sub {
my ($count) = @_;
my @got;
my $edges = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
foreach my $sn ($path->xy_to_n($x+1,$y),
$path->xy_to_n($x-1,$y),
$path->xy_to_n($x,$y+1),
$path->xy_to_n($x,$y-1)) {
if ($sn < $n) {
$edges++;
}
}
push @got, $edges;
}
return \@got;
});
#------------------------------------------------------------------------------
# A141481 -- values as sum of eight surrounding
MyOEIS::compare_values
(anum => q{A141481},
func => sub {
my ($count) = @_;
require Math::BigInt;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
my @got = (1);
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
my $sum = Math::BigInt->new(0);
foreach my $sn ($path->xy_to_n($x+1,$y),
$path->xy_to_n($x-1,$y),
$path->xy_to_n($x,$y+1),
$path->xy_to_n($x,$y-1),
$path->xy_to_n($x+1,$y+1),
$path->xy_to_n($x-1,$y-1),
$path->xy_to_n($x-1,$y+1),
$path->xy_to_n($x+1,$y-1)) {
if ($sn < $n) {
$sum += $got[$sn]; # @got is 0-based
}
}
push @got, $sum;
}
return \@got;
});
#------------------------------------------------------------------------------
# A156859 Y axis positive and negative
MyOEIS::compare_values
(anum => 'A156859',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
my @got = (0);
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n(0, $y);
last unless @got < $count;
push @got, $path->xy_to_n(0, -$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A172294 -- jewels, composite surrounded by 4 primes, starting N=0
MyOEIS::compare_values
(anum => 'A172294',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::SquareSpiral->new (n_start => 0);
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next if Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
if (Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y))
&& Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y))
&& Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1))
&& Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1))
) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A115258 -- isolated primes
MyOEIS::compare_values
(anum => 'A115258',
func => sub {
my ($count) = @_;
my @got;
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
if (! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y+1))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y-1))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y+1))
&& ! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y-1))
) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A214177 -- sum of 4 neighbours
MyOEIS::compare_values
(anum => 'A214177',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
);
}
return \@got;
});
#------------------------------------------------------------------------------
# A214176 -- sum of 8 neighbours
MyOEIS::compare_values
(anum => 'A214176',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
+ $path->xy_to_n($x+1,$y+1)
+ $path->xy_to_n($x-1,$y-1)
+ $path->xy_to_n($x-1,$y+1)
+ $path->xy_to_n($x+1,$y-1)
);
}
return \@got;
});
#------------------------------------------------------------------------------
# A214664 -- X coord of prime N
MyOEIS::compare_values
(anum => 'A214664',
func => sub {
my ($count) = @_;
my @got;
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
# A214665 -- Y coord of prime N
MyOEIS::compare_values
(anum => 'A214665',
func => sub {
my ($count) = @_;
my @got;
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
# A214666 -- X coord of prime N, first to west
MyOEIS::compare_values
(anum => 'A214666',
func => sub {
my ($count) = @_;
my @got;
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
push @got, -$x;
}
return \@got;
});
# A214667 -- Y coord of prime N, first to west
MyOEIS::compare_values
(anum => 'A214667',
func => sub {
my ($count) = @_;
my @got;
require Math::Prime::XS;
for (my $n = $path->n_start; @got < $count; $n++) {
next unless Math::Prime::XS::is_prime($n);
my ($x,$y) = $path->n_to_xy ($n);
push @got, -$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A143856 -- N values ENE slope=2
MyOEIS::compare_values
(anum => 'A143856',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n (2*$i, $i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A143861 -- N values NNE slope=2
MyOEIS::compare_values
(anum => 'A143861',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n ($i, 2*$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A063826 -- direction 1,2,3,4 = E,N,W,S
MyOEIS::compare_values
(anum => 'A063826',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, path_n_dir4_1($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A062410 -- a(n) is sum of existing numbers in row of a(n-1)
MyOEIS::compare_values
(anum => 'A062410',
func => sub {
my ($count) = @_;
my @got;
require Math::BigInt;
my %plotted;
$plotted{0,0} = Math::BigInt->new(1);
my $xmin = 0;
my $ymin = 0;
my $xmax = 0;
my $ymax = 0;
push @got, 1;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($prev_x, $prev_y) = $path->n_to_xy ($n-1);
my ($x, $y) = $path->n_to_xy ($n);
my $total = 0;
if ($y == $prev_y) {
### column: "$ymin .. $ymax at x=$prev_x"
foreach my $y ($ymin .. $ymax) {
$total += $plotted{$prev_x,$y} || 0;
}
} else {
### row: "$xmin .. $xmax at y=$prev_y"
foreach my $x ($xmin .. $xmax) {
$total += $plotted{$x,$prev_y} || 0;
}
}
### total: "$total"
$plotted{$x,$y} = $total;
$xmin = min($xmin,$x);
$xmax = max($xmax,$x);
$ymin = min($ymin,$y);
$ymax = max($ymax,$y);
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A141481 -- plot sum of existing eight surrounding values entered
MyOEIS::compare_values
(anum => q{A141481}, # not in POD
func => sub {
my ($count) = @_;
my @got;
require Math::BigInt;
my %plotted;
$plotted{0,0} = Math::BigInt->new(1);
push @got, 1;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my $value = (
($plotted{$x+1,$y+1} || 0)
+ ($plotted{$x+1,$y} || 0)
+ ($plotted{$x+1,$y-1} || 0)
+ ($plotted{$x-1,$y-1} || 0)
+ ($plotted{$x-1,$y} || 0)
+ ($plotted{$x-1,$y+1} || 0)
+ ($plotted{$x,$y-1} || 0)
+ ($plotted{$x,$y+1} || 0)
);
$plotted{$x,$y} = $value;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A020703 -- permutation read clockwise, ie. transpose Y,X
# also permutation rotate +90, opp direction
MyOEIS::compare_values
(anum => 'A020703',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A121496 -- run lengths of consecutive N in A068225 N at X+1,Y
MyOEIS::compare_values
(anum => 'A121496',
func => sub {
my ($count) = @_;
my @got;
my $num = 0;
my $prev_right_n = A068225(1) - 1; # make first value look like a run
for (my $n = $path->n_start; @got < $count; $n++) {
my $right_n = A068225($n);
if ($right_n == $prev_right_n + 1) {
$num++;
} else {
push @got, $num;
$num = 1;
}
$prev_right_n = $right_n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054551 -- plot Nth prime at each N, values are those primes on X axis
MyOEIS::compare_values
(anum => 'A054551',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n($x,0);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054553 -- plot Nth prime at each N, values are those primes on X=Y diagonal
MyOEIS::compare_values
(anum => 'A054553',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n($x,$x);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054555 -- plot Nth prime at each N, values are those primes on Y axis
MyOEIS::compare_values
(anum => 'A054555',
func => sub {
my ($count) = @_;
my @got;
for (my $y = 0; @got < $count; $y++) {
my $n = $path->xy_to_n(0,$y);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A053999 -- plot Nth prime at each N, values are those primes on South-East
MyOEIS::compare_values
(anum => 'A053999',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n($x,-$x);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054564 -- plot Nth prime at each N, values are those primes on North-West
MyOEIS::compare_values
(anum => 'A054564',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x--) {
my $n = $path->xy_to_n($x,-$x);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054566 -- plot Nth prime at each N, values are those primes on negative X
MyOEIS::compare_values
(anum => 'A054566',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x--) {
my $n = $path->xy_to_n($x,0);
push @got, MyOEIS::ith_prime($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A137928 -- N values on diagonal X=1-Y positive and negative
MyOEIS::compare_values
(anum => 'A137928',
func => sub {
my ($count) = @_;
my @got;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(1-$y,$y);
last unless @got < $count;
if ($y != 0) {
push @got, $path->xy_to_n(1-(-$y),-$y);
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A002061 -- central polygonal numbers, N values on diagonal X=Y pos and neg
MyOEIS::compare_values
(anum => 'A002061',
func => sub {
my ($count) = @_;
my @got;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n($y,$y);
last unless @got < $count;
push @got, $path->xy_to_n(-$y,-$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A016814 -- N values (4n+1)^2 on SE diagonal every second square
MyOEIS::compare_values
(anum => 'A016814',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i+=2) {
push @got, $path->xy_to_n($i,-$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A033952 -- AllDigits on negative Y axis
MyOEIS::compare_values
(anum => 'A033952',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AllDigits;
my $seq = Math::NumSeq::AllDigits->new;
for (my $y = 0; @got < $count; $y--) {
my $n = $path->xy_to_n (0, $y);
push @got, $seq->ith($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A033953 -- AllDigits starting 0, on negative Y axis
MyOEIS::compare_values
(anum => 'A033953',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AllDigits;
my $seq = Math::NumSeq::AllDigits->new;
for (my $y = 0; @got < $count; $y--) {
my $n = $path->xy_to_n (0, $y);
push @got, $seq->ith($n-1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A033988 -- AllDigits starting 0, on negative X axis
MyOEIS::compare_values
(anum => 'A033988',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AllDigits;
my $seq = Math::NumSeq::AllDigits->new;
for (my $x = 0; @got < $count; $x--) {
my $n = $path->xy_to_n ($x, 0);
push @got, $seq->ith($n-1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A033989 -- AllDigits starting 0, on positive Y axis
MyOEIS::compare_values
(anum => 'A033989',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AllDigits;
my $seq = Math::NumSeq::AllDigits->new;
for (my $y = 0; @got < $count; $y++) {
my $n = $path->xy_to_n (0, $y);
push @got, $seq->ith($n-1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A033990 -- AllDigits starting 0, on positive X axis
MyOEIS::compare_values
(anum => 'A033990',
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::AllDigits;
my $seq = Math::NumSeq::AllDigits->new;
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n ($x, 0);
push @got, $seq->ith($n-1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054556 -- N values on Y axis (but OFFSET=1)
MyOEIS::compare_values
(anum => 'A054556',
func => sub {
my ($count) = @_;
my @got;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054567 -- N values on negative X axis
MyOEIS::compare_values
(anum => 'A054567',
func => sub {
my ($count) = @_;
my @got;
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n (-$x, 0);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054554 -- N values on X=Y diagonal
MyOEIS::compare_values
(anum => 'A054554',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n($i,$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054569 -- N values on negative X=Y diagonal, but OFFSET=1
MyOEIS::compare_values
(anum => 'A054569',
func => sub {
my ($count) = @_;
my @got;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n(-$i,-$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A068225 -- permutation N at X+1,Y
MyOEIS::compare_values
(anum => 'A068225',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, A068225($n);
}
return \@got;
});
# starting n=1
sub A068225 {
my ($n) = @_;
my ($x, $y) = $path->n_to_xy ($n);
return $path->xy_to_n ($x+1,$y);
}
#------------------------------------------------------------------------------
# A068226 -- permutation N at X-1,Y
MyOEIS::compare_values
(anum => 'A068226',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($x-1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PeanoCurve-oeis.t 0000644 0001750 0001750 00000040716 12240245042 016465 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 21;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PeanoCurve;
use Math::PlanePath::Diagonals;
use Math::PlanePath::ZOrderCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $peano = Math::PlanePath::PeanoCurve->new;
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
#------------------------------------------------------------------------------
# A145204 -- N+1 of positions of verticals
MyOEIS::compare_values
(anum => 'A145204',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
if ($dx == 0) {
push @got, $n+1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A014578 -- abs(dX), 1=horizontal 0=vertical, extra initial 0
MyOEIS::compare_values
(anum => 'A014578',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
push @got, abs($dx);
}
return \@got;
});
# A182581 -- abs(dY), but OFFSET=1
MyOEIS::compare_values
(anum => 'A182581',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
push @got, abs($dy);
}
return \@got;
});
#------------------------------------------------------------------------------
# A007417 -- N+1 positions of horizontal step, dY==0, abs(dX)=1
# N+1 has even num trailing ternary 0-digits
MyOEIS::compare_values
(anum => 'A007417',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
if ($dy == 0) {
push @got, $n+1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A163532 -- dX a(n)-a(n-1) so extra initial 0
MyOEIS::compare_values
(anum => 'A163532',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got = (0); # extra initial entry N=0 no change
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
push @got, $dx;
}
return \@got;
});
# A163533 -- dY a(n)-a(n-1)
MyOEIS::compare_values
(anum => 'A163533',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PeanoCurve->new;
my @got = (0); # extra initial entry N=0 no change
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $peano->n_to_dxdy($n);
push @got, $dy;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163333 -- Peano N <-> Z-Order radix=3, with digit swaps
{
my $anum = 'A163333';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my @got;
if ($bvalues) {
my $peano = Math::PlanePath::PeanoCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
for (my $n = $zorder->n_start; @got < @$bvalues; $n++) {
my $nn = $n;
{
my ($x,$y) = $zorder->n_to_xy ($nn);
($x,$y) = ($y,$x);
$nn = $zorder->xy_to_n ($x,$y);
}
{
my ($x,$y) = $zorder->n_to_xy ($nn);
$nn = $peano->xy_to_n ($x, $y);
}
{
my ($x,$y) = $zorder->n_to_xy ($nn);
($x,$y) = ($y,$x);
$nn = $zorder->xy_to_n ($x,$y);
}
push @got, $nn;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum");
}
{
my @got;
if ($bvalues) {
my $peano = Math::PlanePath::PeanoCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
for (my $n = 0; @got < @$bvalues; $n++) {
my $nn = $n;
{
my ($x,$y) = $zorder->n_to_xy ($nn);
($x,$y) = ($y,$x);
$nn = $zorder->xy_to_n ($x,$y);
}
{
my ($x,$y) = $peano->n_to_xy ($nn); # other way around
$nn = $zorder->xy_to_n ($x, $y);
}
{
my ($x,$y) = $zorder->n_to_xy ($nn);
($x,$y) = ($y,$x);
$nn = $zorder->xy_to_n ($x,$y);
}
push @got, $nn;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum");
}
}
#------------------------------------------------------------------------------
# A163332 -- Peano N at points in Z-Order radix=3 sequence
{
my $anum = 'A163332';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my @got;
if ($bvalues) {
my $peano = Math::PlanePath::PeanoCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
for (my $n = $zorder->n_start; @got < @$bvalues; $n++) {
my ($x,$y) = $zorder->n_to_xy ($n);
push @got, $peano->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum");
}
{
my @got;
if ($bvalues) {
my $peano = Math::PlanePath::PeanoCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($x,$y) = $peano->n_to_xy ($n); # other way around
push @got, $zorder->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum");
}
}
#------------------------------------------------------------------------------
# A163334 -- diagonals same axis
{
my $anum = 'A163334';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $peano->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163335 -- diagonals same axis, inverse
{
my $anum = 'A163335';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $peano->n_to_xy ($n);
push @got, $diagonal->xy_to_n($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163336 -- diagonals opposite axis
{
my $anum = 'A163336';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $peano->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163337 -- diagonals opposite axis, inverse
{
my $anum = 'A163337';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $peano->n_to_xy ($n);
push @got, $diagonal->xy_to_n($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163338 -- diagonals same axis, 1-based
{
my $anum = 'A163338';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up');
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $peano->xy_to_n ($x, $y) + 1;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163339 -- diagonals same axis, 1-based, inverse
{
my $anum = 'A163339';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up');
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $peano->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163340 -- diagonals same axis, 1 based
{
my $anum = 'A163340';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $peano->xy_to_n($x,$y) + 1;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163341 -- diagonals same axis, 1-based, inverse
{
my $anum = 'A163341';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $peano->n_to_xy ($n);
push @got, $diagonal->xy_to_n($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163342 -- diagonal sums
# no b-file as of Jan 2011
{
my $anum = 'A163342';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $d = 0; @got < @$bvalues; $d++) {
my $sum = 0;
foreach my $x (0 .. $d) {
my $y = $d - $x;
$sum += $peano->xy_to_n ($x, $y);
}
push @got, $sum;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, 'A163342 -- diagonal sums');
}
# A163479 -- diagonal sums div 6
{
my $anum = 'A163479';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $d = 0; @got < @$bvalues; $d++) {
my $sum = 0;
foreach my $x (0 .. $d) {
my $y = $d - $x;
$sum += $peano->xy_to_n ($x, $y);
}
push @got, int($sum/6);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, 'A163479 -- diagonal sums');
}
#------------------------------------------------------------------------------
# A163344 -- N/4 on X=Y diagonal
{
my $anum = 'A163344';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $x = 0; @got < @$bvalues; $x++) {
push @got, int($peano->xy_to_n($x,$x) / 4);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- central diagonal div 4");
}
#------------------------------------------------------------------------------
# A163534 -- absolute direction 0=east, 1=south, 2=west, 3=north
# Y coordinates reckoned down the page, so south is Y increasing
{
my $anum = 'A163534';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($dx, $dy) = $peano->n_to_dxdy ($n);
push @got, MyOEIS::dxdy_to_direction ($dx, $dy);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- absolute direction");
}
#------------------------------------------------------------------------------
# A163535 -- absolute direction transpose 0=east, 1=south, 2=west, 3=north
{
my $anum = 'A163535';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $peano->n_start; @got < @$bvalues; $n++) {
my ($dx, $dy) = $peano->n_to_dxdy ($n);
push @got, MyOEIS::dxdy_to_direction ($dy, $dx);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- absolute direction transpose");
}
#------------------------------------------------------------------------------
# A163536 -- relative direction 0=ahead, 1=right, 2=left
# Y coordinates reckoned down the page
{
my $anum = 'A163536';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my ($n0_x, $n0_y) = $peano->n_to_xy (0);
my ($p_x, $p_y) = $peano->n_to_xy (1);
my ($p_dx, $p_dy) = ($p_x - $n0_x, $p_y - $n0_y);
foreach my $n (2 .. @$bvalues + 1) {
my ($x, $y) = $peano->n_to_xy ($n);
my $dx = $x - $p_x;
my $dy = $y - $p_y;
if ($p_dx) {
if ($dx) {
push @got, 0; # ahead horizontally
} elsif ($dy == $p_dx) {
push @got, 1; # right
} else {
push @got, 2; # left
}
} else {
# p_dy
if ($dy) {
push @got, 0; # ahead horizontally
} elsif ($dx == $p_dy) {
push @got, 2; # left
} else {
push @got, 1; # right
}
}
### $n
### $p_dx
### $p_dy
### $dx
### $dy
### is: "$got[-1] at idx $#got"
($p_dx,$p_dy) = ($dx,$dy);
($p_x,$p_y) = ($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A163537 -- relative direction 0=ahead, 1=right, 2=left
# Y coordinates reckoned down the page
sub transpose {
my ($x, $y) = @_;
return ($y, $x);
}
{
my $anum = 'A163537';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my ($n0_x, $n0_y) = transpose ($peano->n_to_xy (0));
my ($p_x, $p_y) = transpose ($peano->n_to_xy (1));
my ($p_dx, $p_dy) = ($p_x - $n0_x, $p_y - $n0_y);
foreach my $n (2 .. @$bvalues + 1) {
my ($x, $y) = transpose ($peano->n_to_xy ($n));
my $dx = $x - $p_x;
my $dy = $y - $p_y;
if ($p_dx) {
if ($dx) {
push @got, 0; # ahead horizontally
} elsif ($dy == $p_dx) {
push @got, 1; # right
} else {
push @got, 2; # left
}
} else {
# p_dy
if ($dy) {
push @got, 0; # ahead horizontally
} elsif ($dx == $p_dy) {
push @got, 2; # left
} else {
push @got, 1; # right
}
}
### $n
### $p_dx
### $p_dy
### $dx
### $dy
### is: "$got[-1] at idx $#got"
($p_dx,$p_dy) = ($dx,$dy);
($p_x,$p_y) = ($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction transposed");
}
exit 0;
Math-PlanePath-113/xt/oeis/HilbertCurve-oeis.t 0000644 0001750 0001750 00000073712 12136177301 017024 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Test;
plan tests => 38;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::HilbertCurve;
use Math::PlanePath::Diagonals;
use Math::PlanePath::ZOrderCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $hilbert = Math::PlanePath::HilbertCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new;
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
#------------------------------------------------------------------------------
sub zorder_perm {
my ($n) = @_;
my ($x, $y) = $zorder->n_to_xy ($n);
return $hilbert->xy_to_n ($x, $y);
}
sub zorder_perm_inverse {
my ($n) = @_;
my ($x, $y) = $hilbert->n_to_xy ($n);
return $zorder->xy_to_n ($x, $y);
}
sub zorder_perm_rep {
my ($n, $reps) = @_;
foreach (1 .. $reps) {
my ($x, $y) = $zorder->n_to_xy ($n);
$n = $hilbert->xy_to_n ($x, $y);
}
return $n;
}
sub zorder_cycle_length {
my ($n) = @_;
my $count = 1;
my $p = $n;
for (;;) {
$p = zorder_perm($p);
if ($p == $n) {
last;
}
$count++;
}
return $count;
}
sub zorder_is_2cycle {
my ($n) = @_;
my $p1 = zorder_perm($n);
if ($p1 == $n) { return 0; }
my $p2 = zorder_perm($p1);
return ($p2 == $n);
}
sub zorder_is_3cycle {
my ($n) = @_;
my $p1 = zorder_perm($n);
if ($p1 == $n) { return 0; }
my $p2 = zorder_perm($p1);
if ($p2 == $n) { return 0; }
my $p3 = zorder_perm($p2);
return ($p3 == $n);
}
#------------------------------------------------------------------------------
# A163538 -- dX
# extra first entry for N=0 no change
MyOEIS::compare_values
(anum => 'A163538',
func => sub {
my ($count) = @_;
my @got = (0);
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($dx, $dy) = $hilbert->n_to_dxdy ($n);
push @got, $dx;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163539 -- dY
# extra first entry for N=0 no change
MyOEIS::compare_values
(anum => 'A163539',
func => sub {
my ($count) = @_;
my @got = (0);
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($dx, $dy) = $hilbert->n_to_dxdy ($n);
push @got, $dy;
}
return \@got;
});
#------------------------------------------------------------------------------
# A166041 - N in Peano order
MyOEIS::compare_values
(anum => 'A166041',
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $peano = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $peano->n_start; @got < $count; $n++) {
my ($x, $y) = $peano->n_to_xy($n);
push @got, $hilbert->xy_to_n ($x, $y);
}
return \@got;
});
# inverse Peano in Hilbert order
MyOEIS::compare_values
(anum => 'A166042',
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $peano = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($x, $y) = $hilbert->n_to_xy($n);
push @got, $peano->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A165465 -- N where Hilbert and Peano same X,Y
MyOEIS::compare_values
(anum => 'A165465',
max_value => 100000,
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $peano = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($hx,$hy) = $hilbert->n_to_xy($n);
my ($px,$py) = $peano->n_to_xy($n);
if ($hx == $px && $hy == $py) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A165464 -- dx^2+dy^2 of Hilbert->Peano
MyOEIS::compare_values
(anum => 'A165464',
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $peano = Math::PlanePath::PeanoCurve->new;
my @got;
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($hx,$hy) = $hilbert->n_to_xy($n);
my ($px,$py) = $peano->n_to_xy($n);
push @got, ($px-$hx)**2 + ($py-$hy)**2;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163540 -- absolute direction 0=east, 1=south, 2=west, 3=north
# Y coordinates reckoned down the page, so south is Y increasing
MyOEIS::compare_values
(anum => 'A163540',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $hilbert->n_start; @got < $count; $n++) {
my ($dx, $dy) = $hilbert->n_to_dxdy ($n);
push @got, MyOEIS::dxdy_to_direction ($dx, $dy);
}
return \@got;
});
#------------------------------------------------------------------------------
# A163891 - positions where cycle length some new previously unseen value
#
# len: 1, 1, 2, 2, 6, 3, 3, 6, 6, 6, 3, 3, 6, 3, 6, 3, 1, 3, 3, 3, 1, 1, 2, 2,
# ^
# 91: 0 2 4 5
{
my $anum = 'A163891';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 20);
my @got;
if ($bvalues) {
my %seen;
for (my $n = 0; @got < @$bvalues; $n++) {
my $len = zorder_cycle_length($n);
if (! $seen{$len}) {
push @got, $n;
$seen{$len} = 1;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - cycle length by N");
}
#------------------------------------------------------------------------------
# A163893 - first diffs of positions where cycle length some new unseen value
{
my $anum = 'A163893';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 20);
my @got;
if ($bvalues) {
my %seen = (1 => 1);
my $prev = 0;
for (my $n = 0; @got < @$bvalues; $n++) {
my $len = zorder_cycle_length($n);
if (! $seen{$len}) {
push @got, $n-$prev;
$prev = $n;
$seen{$len} = 1;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - cycle length by N");
}
#------------------------------------------------------------------------------
# A163896 - value where A163894 is a new high
{
my $anum = 'A163896';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 8);
my @got;
if ($bvalues) {
my $high = -1;
for (my $n = 0; @got < @$bvalues; $n++) {
my $value = A163894_perm_n_not($n);
if ($value > $high) {
$high = $value;
push @got, $value;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..6]));
MyTestHelpers::diag ("got: ",join(',',@got[0..6]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163895 - position where A163894 is a new high
{
my $anum = 'A163895';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 8);
my @got;
if ($bvalues) {
my $high = -1;
for (my $n = 0; @got < @$bvalues; $n++) {
my $value = A163894_perm_n_not($n);
if ($value > $high) {
$high = $value;
push @got, $n;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..6]));
MyTestHelpers::diag ("got: ",join(',',@got[0..6]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163894 - first i for which (perm^n)[i] != i
{
my $anum = 'A163894';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 200);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
push @got, A163894_perm_n_not($n);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..7]));
MyTestHelpers::diag ("got: ",join(',',@got[0..7]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
sub A163894_perm_n_not {
my ($n) = @_;
if ($n == 0) {
return 0;
}
for (my $i = 0; ; $i++) {
my $p = zorder_perm_rep ($i, $n);
if ($p != $i) {
return $i;
}
}
}
#------------------------------------------------------------------------------
# A163909 - num 3-cycles in 4^k blocks, even k only
{
my $anum = 'A163909';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 5);
my @got;
if ($bvalues) {
my $target = 1;
my $target_even = 1;
my $count = 0;
my @seen;
for (my $n = 0; @got < @$bvalues; $n++) {
if ($n >= $target) {
if ($target_even) {
push @got, $count;
}
$target_even ^= 1;
$count = 0;
$target *= 4;
@seen = ();
$#seen = $target; # pre-extend
}
unless ($seen[$n]) {
my $p1 = zorder_perm($n);
next if $p1 == $n; # a fixed point
my $p2 = zorder_perm($p1);
next if $p2 == $n; # a 2-cycle
my $p3 = zorder_perm($p2);
next unless $p3 == $n; # not a 3-cycle
$count++;
$seen[$n] = 1;
$seen[$p1] = 1;
$seen[$p2] = 1;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..7]));
MyTestHelpers::diag ("got: ",join(',',@got[0..7]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163914 - num 3-cycles in 4^k blocks
{
my $anum = 'A163914';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum,
max_count => 8);
my @got;
if ($bvalues) {
my $target = 1;
my $count = 0;
my @seen;
for (my $n = 0; @got < @$bvalues; $n++) {
if ($n >= $target) {
push @got, $count;
$count = 0;
$target *= 4;
@seen = ();
$#seen = $target; # pre-extend
}
unless ($seen[$n]) {
my $p1 = zorder_perm($n);
next if $p1 == $n; # a fixed point
my $p2 = zorder_perm($p1);
next if $p2 == $n; # a 2-cycle
my $p3 = zorder_perm($p2);
next unless $p3 == $n; # not a 3-cycle
$count++;
$seen[$n] = 1;
$seen[$p1] = 1;
$seen[$p2] = 1;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163908 - perm twice, by diagonals, inverse
{
my $anum = 'A163908';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new
(direction => 'up'); # from same axis as Hilbert
for (my $n = 0; @got < @$bvalues; $n++) {
my $nn = zorder_perm_inverse(zorder_perm_inverse($n));
my ($x, $y) = $zorder->n_to_xy ($nn);
my $dn = $diagonal->xy_to_n ($x, $y);
push @got, $dn-1;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - double-perm by diagonals, inverse");
}
#------------------------------------------------------------------------------
# A163907 - perm twice, by diagonals
{
my $anum = 'A163907';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new
(direction => 'up'); # from same axis as Hilbert
for (my $dn = $diagonal->n_start; @got < @$bvalues; $dn++) {
my ($x, $y) = $diagonal->n_to_xy ($dn);
my $n = $zorder->xy_to_n ($x, $y);
push @got, zorder_perm(zorder_perm($n));
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - double-perm by diagonals");
}
#------------------------------------------------------------------------------
# A163904 - cycle length by diagonals
{
my $anum = 'A163904';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new
(direction => 'up'); # from same axis as Hilbert
for (my $dn = $diagonal->n_start; @got < @$bvalues; $dn++) {
my ($x, $y) = $diagonal->n_to_xy ($dn);
my $hn = $hilbert->xy_to_n ($x, $y);
push @got, zorder_cycle_length($hn);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - cycle length by diagonals");
}
#------------------------------------------------------------------------------
# A163890 - cycle length by N
{
my $anum = 'A163890';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum,
max_count => 10000);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
push @got, zorder_cycle_length($n);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - cycle length by N");
}
#------------------------------------------------------------------------------
# A163900 - squared distance between Hilbert and Z order
{
my $anum = 'A163900';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
my ($hx, $hy) = $hilbert->n_to_xy ($n);
my ($zx, $zy) = $zorder->n_to_xy ($n);
my $dx = $hx - $zx;
my $dy = $hy - $zy;
push @got, $dx**2 + $dy**2;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..7]));
MyTestHelpers::diag ("got: ",join(',',@got[0..7]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1,
"$anum - squared distance between Hilbert and ZOrder");
}
#------------------------------------------------------------------------------
# A163912 - LCM of cycle lengths in 4^k blocks
{
my $anum = 'A163912';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 6);
my @got;
if ($bvalues) {
my $target = 1;
my $max = 0;
my %lengths;
for (my $n = 0; @got < @$bvalues; $n++) {
if ($n >= $target) {
push @got, lcm(keys %lengths);
$target *= 4;
%lengths = ();
}
$lengths{zorder_cycle_length($n)} = 1;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..7]));
MyTestHelpers::diag ("got: ",join(',',@got[0..7]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
use Math::PlanePath::GcdRationals;
sub lcm {
my $lcm = 1;
foreach my $n (@_) {
my $gcd = Math::PlanePath::GcdRationals::_gcd($lcm,$n);
$lcm = $lcm * $n / $gcd;
}
return $lcm;
}
#------------------------------------------------------------------------------
# A163911 - max cycle in 4^k blocks
{
my $anum = 'A163911';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 7);
my @got;
if ($bvalues) {
my $target = 1;
my $max = 0;
for (my $n = 0; @got < @$bvalues; $n++) {
if ($n >= $target) {
push @got, $max;
$max = 0;
$target *= 4;
}
$max = max ($max, zorder_cycle_length($n));
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# #------------------------------------------------------------------------------
# # A147600 - num fixed points in 4^k blocks
# {
# my $anum = 'A147600';
# my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count=>9);
# my @got;
# if ($bvalues) {
# my $target = 1;
# my $count = 0;
# for (my $n = 0; @got < @$bvalues; $n++) {
# if ($n >= $target) {
# push @got, $count;
# $count = 0;
# $target *= 4;
# }
# if ($n == zorder_perm($n)) {
# $count++;
# }
# }
#
# if (! numeq_array(\@got, $bvalues)) {
# MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
# MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
# }
# }
# skip (! $bvalues,
# numeq_array(\@got, $bvalues),
# 1);
# }
#------------------------------------------------------------------------------
# A163910 - num cycles in 4^k blocks
{
my $anum = 'A163910';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum, max_count => 9);
my @got;
if ($bvalues) {
my $target = 1;
my $count = 0;
my @seen;
for (my $n = 0; @got < @$bvalues; $n++) {
if ($n >= $target) {
push @got, $count;
$count = 0;
$target *= 4;
@seen = ();
$#seen = $target; # pre-extend
}
$count++;
my $p = $n;
for (;;) {
$p = zorder_perm($p);
if ($seen[$p]) {
$count--;
last;
}
$seen[$p] = 1;
last if $p == $n;
}
$seen[$n] = 1;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163355 - in Z order sequence
MyOEIS::compare_values
(anum => 'A163355',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 0; @got < $count; $n++) {
push @got, zorder_perm($n);
}
return \@got;
});
# A163356 - inverse
{
my $anum = 'A163356';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
my ($x, $y) = $hilbert->n_to_xy ($n);
push @got, $zorder->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163905 - applied twice
{
my $anum = 'A163905';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
push @got, zorder_perm(zorder_perm($n));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163915 - applied three times
{
my $anum = 'A163915';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
push @got, zorder_perm(zorder_perm(zorder_perm($n)));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163901 - fixed-point N values
{
my $anum = 'A163901';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
if (zorder_perm($n) == $n) {
push @got, $n;
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163902 - 2-cycle N values
{
my $anum = 'A163902';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
if (zorder_is_2cycle($n)) {
push @got, $n;
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163903 - 3-cycle N values
{
my $anum = 'A163903';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
if (zorder_is_3cycle($n)) {
push @got, $n;
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163357 - in diagonal sequence
{
my $anum = 'A163357';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($y, $x) = $diagonal->n_to_xy ($n);
push @got, $hilbert->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163358 - inverse
{
my $anum = 'A163358';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $hilbert->n_start; @got < @$bvalues; $n++) {
my ($y, $x) = $hilbert->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163359 - in diagonal sequence, opp sides
{
my $anum = 'A163359';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new
(direction => 'down'); # from opposite side
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $hilbert->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163360 - inverse
{
my $anum = 'A163360';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $hilbert->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $hilbert->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A163361 - diagonal sequence, one based, same side
{
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up');
{
my $anum = 'A163361';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $hilbert->xy_to_n ($x, $y) + 1; # 1-based Hilbert
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163362 - inverse
{
my $anum = 'A163362';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $hilbert->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $hilbert->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y); # 1-based Hilbert
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
}
#------------------------------------------------------------------------------
# A163363 - diagonal sequence, one based, opp sides
{
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
{
my $anum = 'A163363';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $diagonal->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $hilbert->xy_to_n ($x, $y) + 1;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
# A163364 - inverse
{
my $anum = 'A163364';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $hilbert->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $hilbert->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
}
#------------------------------------------------------------------------------
# A163365 - diagonal sums
{
my $anum = 'A163365';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $d = 0; @got < @$bvalues; $d++) {
my $sum = 0;
foreach my $x (0 .. $d) {
my $y = $d - $x;
$sum += $hilbert->xy_to_n ($x, $y);
}
push @got, $sum;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - diagonal sums");
}
# A163477 - diagonal sums divided by 4
{
my $anum = 'A163477';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $d = 0; @got < @$bvalues; $d++) {
my $sum = 0;
foreach my $x (0 .. $d) {
my $y = $d - $x;
$sum += $hilbert->xy_to_n ($x, $y);
}
push @got, int($sum/4);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - diagonal sums divided by 4");
}
#------------------------------------------------------------------------------
# A163541 -- absolute direction transpose 0=east, 1=south, 2=west, 3=north
{
my $anum = 'A163541';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $hilbert->n_start; @got < @$bvalues; $n++) {
my ($dx, $dy) = $hilbert->n_to_dxdy ($n);
($dx,$dy) = ($dy,$dx); # transpose
push @got, MyOEIS::dxdy_to_direction ($dx, $dy);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- absolute direction transpose");
}
#------------------------------------------------------------------------------
# A163542 -- relative direction 0=ahead, 1=right, 2=left
# Y coordinates reckoned down the page
{
my $anum = 'A163542';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my ($n0_x, $n0_y) = $hilbert->n_to_xy (0);
my ($p_x, $p_y) = $hilbert->n_to_xy (1);
my ($p_dx, $p_dy) = ($p_x - $n0_x, $p_y - $n0_y);
foreach my $n (2 .. @$bvalues + 1) {
my ($x, $y) = $hilbert->n_to_xy ($n);
my $dx = $x - $p_x;
my $dy = $y - $p_y;
if ($p_dx) {
if ($dx) {
push @got, 0; # ahead horizontally
} elsif ($dy == $p_dx) {
push @got, 1; # right
} else {
push @got, 2; # left
}
} else {
# p_dy
if ($dy) {
push @got, 0; # ahead horizontally
} elsif ($dx == $p_dy) {
push @got, 2; # left
} else {
push @got, 1; # right
}
}
### $n
### $p_dx
### $p_dy
### $dx
### $dy
### is: "$got[-1] at idx $#got"
($p_dx,$p_dy) = ($dx,$dy);
($p_x,$p_y) = ($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction");
}
#------------------------------------------------------------------------------
# A163543 -- relative direction 0=ahead, 1=right, 2=left
# Y coordinates reckoned down the page
sub transpose {
my ($x, $y) = @_;
return ($y, $x);
}
{
my $anum = 'A163543';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my ($n0_x, $n0_y) = transpose ($hilbert->n_to_xy (0));
my ($p_x, $p_y) = transpose ($hilbert->n_to_xy (1));
my ($p_dx, $p_dy) = ($p_x - $n0_x, $p_y - $n0_y);
foreach my $n (2 .. @$bvalues + 1) {
my ($x, $y) = transpose ($hilbert->n_to_xy ($n));
my $dx = ($x - $p_x);
my $dy = ($y - $p_y);
if ($p_dx) {
if ($dx) {
push @got, 0; # ahead horizontally
} elsif ($dy == $p_dx) {
push @got, 1; # right
} else {
push @got, 2; # left
}
} else {
# p_dy
if ($dy) {
push @got, 0; # ahead horizontally
} elsif ($dx == $p_dy) {
push @got, 2; # left
} else {
push @got, 1; # right
}
}
### $n
### $p_dx
### $p_dy
### $dx
### $dy
### is: "$got[-1] at idx $#got"
($p_dx,$p_dy) = ($dx,$dy);
($p_x,$p_y) = ($x,$y);
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- relative direction transposed");
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DragonMidpoint-oeis.t 0000644 0001750 0001750 00000011501 12153014042 017317 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 3;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DragonMidpoint;
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A077860 -- Y at N=2^k, starting k=1 N=2
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
# Re -(i+1)^k + i-1
{
require Math::Complex;
my $path = Math::PlanePath::DragonMidpoint->new;
my $b = Math::Complex->make(1,1);
foreach my $k (1 .. 10) {
my $n = 2**$k;
my ($x,$y) = $path->n_to_xy($n);
my $c = $b; foreach (1 .. $k) { $c *= $b; }
$c *= Math::Complex->make(0,-1);
$c += Math::Complex->make(-1,1);
ok ($c->Re, $x);
ok ($c->Im, $y);
# print $x,",";
# print $c->Re,",";
# print $c->Im,",";
}
}
MyOEIS::compare_values
(anum => 'A077860',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::DragonMidpoint->new;
my @got;
for (my $n = $bigclass->new(2); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A073089 -- abs(dY), so 1 if step vertical, 0 if horizontal
# with extra leading 0
MyOEIS::compare_values
(anum => 'A073089',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::DragonMidpoint->new;
my @got = (0);
my ($prev_x, $prev_y) = $path->n_to_xy (0);
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($x == $prev_x) {
push @got, 1; # vertical
} else {
push @got, 0; # horizontal
}
($prev_x,$prev_y) = ($x,$y);
}
return \@got;
});
# A073089_func vs b-file
MyOEIS::compare_values
(anum => 'A073089',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 1; @got < $count; $n++) {
push @got, A073089_func($n);
}
return \@got;
});
# A073089_func vs path
{
my $path = Math::PlanePath::DragonMidpoint->new;
my ($prev_x, $prev_y) = $path->n_to_xy (0);
my $bad = 0;
foreach my $n (0 .. 0x2FFF) {
my ($x, $y) = $path->n_to_xy ($n);
my ($nx, $ny) = $path->n_to_xy ($n+1);
my $path_value = ($x == $nx
? 1 # vertical
: 0); # horizontal
my $a_value = A073089_func($n+2);
if ($path_value != $a_value) {
MyTestHelpers::diag ("diff n=$n path=$path_value acalc=$a_value");
MyTestHelpers::diag (" xy=$x,$y nxy=$nx,$ny");
last if ++$bad > 10;
}
}
ok ($bad, 0, "A073089_func()");
}
sub A073089_func {
my ($n) = @_;
### A073089_func: $n
for (;;) {
if ($n <= 1) { return 0; }
if (($n % 4) == 2) { return 0; }
if (($n % 8) == 7) { return 0; }
if (($n % 16) == 13) { return 0; }
if (($n % 4) == 0) { return 1; }
if (($n % 8) == 3) { return 1; }
if (($n % 16) == 5) { return 1; }
if (($n % 8) == 1) {
$n = ($n-1)/2+1; # 8n+1 -> 4n+1
next;
}
die "oops";
}
}
# absdy_bitwise() vs path
{
my $path = Math::PlanePath::DragonMidpoint->new;
my ($prev_x, $prev_y) = $path->n_to_xy (0);
my $bad = 0;
foreach my $n (0 .. 0x2FFF) {
my ($x, $y) = $path->n_to_xy ($n);
my ($nx, $ny) = $path->n_to_xy ($n+1);
my $path_value = ($x == $nx
? 1 # vertical
: 0); # horizontal
my $a_value = absdy_bitwise($n);
if ($path_value != $a_value) {
MyTestHelpers::diag ("diff n=$n path=$path_value acalc=$a_value");
MyTestHelpers::diag (" xy=$x,$y nxy=$nx,$ny");
last if ++$bad > 10;
}
}
ok ($bad, 0, "absdy_bitwise()");
}
sub absdy_bitwise {
my ($n) = @_;
return ($n & 1) ^ bit_above_lowest_zero($n);
}
sub bit_above_lowest_zero {
my ($n) = @_;
for (;;) {
if (($n % 2) == 0) {
last;
}
$n = int($n/2);
}
$n = int($n/2);
return ($n % 2);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/FractionsTree-oeis.t 0000644 0001750 0001750 00000007167 12136177301 017177 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::FractionsTree;
# uncomment this to run the ### lines
#use Smart::Comments '###';
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
#------------------------------------------------------------------------------
# A093873 -- Kepler numerators
# {
# my $path = Math::PlanePath::FractionsTree->new (tree_type => 'Kepler');
# my $anum = 'A093873';
# my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
# my @got;
# if ($bvalues) {
# foreach my $n (1 .. @$bvalues) {
# my ($x, $y) = $path->n_to_xy (int(($n+1)/2));
# push @got, $x;
# }
# }
# skip (! $bvalues,
# numeq_array(\@got, $bvalues),
# 1, "$anum -- Kepler tree numerators");
# }
#
# sub sans_high_bit {
# my ($n) = @_;
# return $n ^ high_bit($n);
# }
# sub high_bit {
# my ($n) = @_;
# my $bit;
# for ($bit = 1; $bit <= $n; $bit <<= 1) {
# $bit <<= 1;
# }
# return $bit >> 1;
# }
#------------------------------------------------------------------------------
# A093875 -- Kepler denominators
# {
# my $path = Math::PlanePath::FractionsTree->new (tree_type => 'Kepler');
# my $anum = 'A093875';
# my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
# my @got;
# if ($bvalues) {
# foreach my $n (2 .. @$bvalues) {
# my ($x, $y) = $path->n_to_xy (int($n/2));
# push @got, $y;
# }
# }
# skip (! $bvalues,
# numeq_array(\@got, $bvalues),
# 1, "$anum -- Kepler tree denominators");
# }
#------------------------------------------------------------------------------
# A086593 -- Kepler half-tree denominators, every second value
{
my $anum = 'A086593';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my $path = Math::PlanePath::FractionsTree->new (tree_type => 'Kepler');
my @got;
if ($bvalues) {
for (my $n = $path->n_start; @got < @$bvalues; $n += 2) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- Kepler half-tree denominators every second value");
}
# is also the sum X+Y, skipping initial 2
{
my $path = Math::PlanePath::FractionsTree->new (tree_type => 'Kepler');
my @got;
if ($bvalues) {
push @got, 2;
for (my $n = $path->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x+$y;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum -- as sum X+Y");
}
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CoprimeColumns-oeis.t 0000644 0001750 0001750 00000017241 12136177302 017361 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 10;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CoprimeColumns;
# uncomment this to run the ### lines
# use Smart::Comments '###';
my $path = Math::PlanePath::CoprimeColumns->new;
#------------------------------------------------------------------------------
# A127368 - Y coordinate of coprimes, 0 for non-coprimes
{
my $anum = 'A127368';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my $good = 1;
my $count = 0;
if ($bvalues) {
my $x = 1;
my $y = 1;
for (my $i = 0; $i < @$bvalues; $i++) {
my $want = $bvalues->[$i];
my $got = (Math::PlanePath::CoprimeColumns::_coprime($x,$y)
? $y : 0);
if ($got != $want) {
MyTestHelpers::diag ("wrong _coprime($x,$y)=$got want=$want at i=$i of $filename");
$good = 0;
}
$y++;
if ($y > $x) {
$x++;
$y = 1;
}
$count++;
}
}
ok ($good, 1, "$anum count $count");
}
MyOEIS::compare_values
(anum => q{A127368},
func => sub {
my ($count) = @_;
my @got;
OUTER: for (my $x = 1; ; $x++) {
foreach my $y (1 .. $x) {
if ($path->xy_is_visited($x,$y)) {
push @got, $y;
} else {
push @got, 0;
}
last OUTER if @got >= $count;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A179594 - column of nxn unvisited block
# is X here but Y in A179594 since it goes as rows of coprimes rather than
# columns
MyOEIS::compare_values
(anum => 'A179594',
max_count => 3,
func => sub {
my ($count) = @_;
my @got;
my $x = 1;
for (my $size = 1; @got < $count; $size++) {
for ( ; ! have_unvisited_square($x,$size); $x++) {
}
push @got, $x;
}
return \@got;
});
# return true if there's a $size by $size unvisited square somewhere in
# column $x
sub have_unvisited_square {
my ($x, $size) = @_;
### have_unvisited_square(): $x,$size
my $count = 0;
foreach my $y (2 .. $x) {
if (have_unvisited_line($x,$y,$size)) {
$count++;
if ($count >= $size) {
### found at: "x=$x, y=$y count=$count"
return 1;
}
} else {
$count = 0;
}
}
return 0;
}
# return true if $x,$y is the start (the leftmost point) of a $size length
# line of unvisited points
sub have_unvisited_line {
my ($x,$y, $size) = @_;
foreach my $i (0 .. $size-1) {
if ($path->xy_is_visited($x,$y)) {
return 0;
}
$x++;
}
return 1;
}
#------------------------------------------------------------------------------
# A002088 - totient sum along X axis, or diagonal of n_start=1
MyOEIS::compare_values
(anum => 'A002088',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::CoprimeColumns->new (n_start => 1);
my @got = (0, 1);
for (my $x = 2; @got < $count; $x++) {
push @got, $path->xy_to_n($x,$x-1);
}
return \@got;
});
MyOEIS::compare_values
(anum => qq{A002088},
func => sub {
my ($count) = @_;
my @got;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054428 - inverse, permutation SB N -> coprime columns N
MyOEIS::compare_values
(anum => 'A054428',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::RationalsTree;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
for (my $n = 0; @got < $count; $n++) {
my $sn = insert_second_highest_bit_one($n);
my ($x,$y) = $sb->n_to_xy ($sn);
### sb: "$x/$y"
my $cn = $path->xy_to_n($x,$y);
if (! defined $cn) {
die "oops, SB $x,$y";
}
push @got, $cn+1;
}
return \@got;
});
sub insert_second_highest_bit_one {
my ($n) = @_;
my $str = sprintf ('%b', $n);
substr($str,1,0) = '1';
return oct("0b$str");
}
# # ### assert: delete_second_highest_bit(1) == 1
# # ### assert: delete_second_highest_bit(2) == 1
# ### assert: delete_second_highest_bit(4) == 2
# ### assert: delete_second_highest_bit(5) == 3
#------------------------------------------------------------------------------
# A054427 - permutation coprime columns N -> SB N
MyOEIS::compare_values
(anum => 'A054427',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::RationalsTree;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my $n = 0;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy ($n++);
### frac: "$x/$y"
my $sn = $sb->xy_to_n($x,$y);
push @got, delete_second_highest_bit($sn) + 1;
}
return \@got;
});
sub delete_second_highest_bit {
my ($n) = @_;
my $bit = 1;
my $ret = 0;
while ($bit <= $n) {
$ret |= ($n & $bit);
$bit <<= 1;
}
$bit >>= 1;
$ret &= ~$bit;
$bit >>= 1;
$ret |= $bit;
# ### $ret
# ### $bit
return $ret;
}
# ### assert: delete_second_highest_bit(1) == 1
# ### assert: delete_second_highest_bit(2) == 1
### assert: delete_second_highest_bit(4) == 2
### assert: delete_second_highest_bit(5) == 3
#------------------------------------------------------------------------------
# A121998 - list of <=k with a common factor
MyOEIS::compare_values
(anum => 'A121998',
func => sub {
my ($count) = @_;
my @got;
OUTER: for (my $x = 2; ; $x++) {
for (my $y = 1; $y <= $x; $y++) {
if (! $path->xy_is_visited($x,$y)) {
push @got, $y;
last OUTER unless @got < $count;
}
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A054521 - by columns 1 if coprimes, 0 if not
{
my $anum = 'A054521';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my $good = 1;
my $count = 0;
if ($bvalues) {
my $x = 1;
my $y = 1;
for (my $i = 0; $i < @$bvalues; $i++) {
my $want = $bvalues->[$i];
my $got = (Math::PlanePath::CoprimeColumns::_coprime($x,$y)
? 1 : 0);
if ($got != $want) {
MyTestHelpers::diag ("wrong _coprime($x,$y)=$got want=$want at i=$i of $filename");
$good = 0;
}
$y++;
if ($y > $x) {
$x++;
$y = 1;
}
$count++;
}
}
ok ($good, 1, "$anum count $count");
}
}
MyOEIS::compare_values
(anum => q{A054521},
func => sub {
my ($count) = @_;
my @got;
OUTER: for (my $x = 1; ; $x++) {
foreach my $y (1 .. $x) {
if ($path->xy_is_visited($x,$y)) {
push @got, 1;
} else {
push @got, 0;
}
last OUTER if @got >= $count;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/FactorRationals-oeis.t 0000644 0001750 0001750 00000015213 12236225213 017506 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 14;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::FactorRationals;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $path = Math::PlanePath::FactorRationals->new;
#------------------------------------------------------------------------------
# A053985 - negabinary pos->pn
MyOEIS::compare_values
(anum => 'A053985',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 0; @got < $count; $i++) {
push @got, Math::PlanePath::FactorRationals::_pos_to_pn__negabinary($i);
}
return \@got;
});
# A005351 pn(+ve) -> pos
MyOEIS::compare_values
(anum => 'A005351',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 0; @got < $count; $i++) {
push @got, Math::PlanePath::FactorRationals::_pn_to_pos__negabinary($i);
}
return \@got;
});
# A039724 pn(+ve) -> pos, in binary
MyOEIS::compare_values
(anum => 'A039724',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 0; @got < $count; $i++) {
push @got, sprintf('%b', Math::PlanePath::FactorRationals::_pn_to_pos__negabinary($i));
}
return \@got;
});
# A005352 pn(-ve) -> pos
MyOEIS::compare_values
(anum => 'A005352',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = -1; @got < $count; $i--) {
push @got, Math::PlanePath::FactorRationals::_pn_to_pos__negabinary($i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A065620 - revbinary pos->pn
MyOEIS::compare_values
(anum => 'A065620',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 1; @got < $count; $i++) {
push @got, Math::PlanePath::FactorRationals::_pos_to_pn__revbinary($i);
}
return \@got;
});
# A065621 pn(+ve) -> pos
MyOEIS::compare_values
(anum => 'A065621',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 1; @got < $count; $i++) {
push @got, Math::PlanePath::FactorRationals::_pn_to_pos__revbinary($i);
}
return \@got;
});
# A048724 pn(-ve) -> pos n XOR 2n
MyOEIS::compare_values
(anum => 'A048724',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::FactorRationals;
for (my $i = 0; @got < $count; $i--) {
push @got, Math::PlanePath::FactorRationals::_pn_to_pos__revbinary($i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A072345 -- X or Y at N=2^k, being alternately 1 and 2^k
MyOEIS::compare_values
(anum => 'A072345',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 2; @got < $count; $n *= 2) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
# last unless @got < $count;
# push @got, $y;
}
return\@got;
});
MyOEIS::compare_values
(anum => q{A072345},
func => sub {
my ($count) = @_;
my @got;
for (my $n = 1; @got < $count; $n *= 2) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return\@got;
});
#------------------------------------------------------------------------------
# A011262 -- N at transpose Y/X
# cf A011264
MyOEIS::compare_values
(anum => 'A011262',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return\@got;
});
sub calc_A011262 {
my ($n) = @_;
my $ret = 1;
for (my $p = 2; $p <= $n; $p++) {
if (($n % $p) == 0) {
my $count = 0;
while (($n % $p) == 0) {
$n /= $p;
$count++;
}
$count = ($count & 1 ? $count+1 : $count-1);
# $count++;
# $count ^= 1;
# $count--;
$ret *= $p ** $count;
}
}
return $ret;
}
MyOEIS::compare_values
(anum => 'A011262',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, calc_A011262($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A102631 - n^2/squarefreekernel(n), is column at X=1
MyOEIS::compare_values
(anum => 'A102631',
func => sub {
my ($count) = @_;
my @got;
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n (1, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A060837 - permutation DiagonalRationals N -> FactorRationals N
MyOEIS::compare_values
(anum => 'A060837',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::DiagonalRationals;
my $columns = Math::PlanePath::DiagonalRationals->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $columns->n_to_xy ($n);
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A071970 - permutation Stern a[i]/[ai+1] which is Calkin-Wilf N -> power N
MyOEIS::compare_values
(anum => 'A071970',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::RationalsTree;
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $sb->n_to_xy ($n);
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PentSpiral-oeis.t 0000644 0001750 0001750 00000002641 12164405451 016501 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PentSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A134238 - N on South-West diagonal
MyOEIS::compare_values
(anum => 'A134238',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PentSpiral->new;
my @got;
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n(-$i,-$i);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CCurve-oeis.t 0000644 0001750 0001750 00000013017 12207205523 015602 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 7;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $path = Math::PlanePath::CCurve->new;
# return 0,1,2,3 turn
sub path_n_turn {
my ($path, $n) = @_;
my $prev_dir = path_n_dir ($path, $n-1);
my $dir = path_n_dir ($path, $n);
return ($dir - $prev_dir) % 4;
}
# return 0,1,2,3
sub path_n_dir {
my ($path, $n) = @_;
my ($dx,$dy) = $path->n_to_dxdy($n) or die "Oops, no point at ",$n;
return dxdy_to_dir ($dx, $dy);
}
# return 0,1,2,3, with Y reckoned increasing upwards
sub dxdy_to_dir {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # north
if ($dy < 0) { return 3; } # south
}
#------------------------------------------------------------------------------
# A096268 - morphism turn 1=straight,0=not-straight
# but OFFSET=0 is turn at N=1
MyOEIS::compare_values
(anum => 'A096268',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'CCurve',
turn_type => 'LSR');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value == 0 ? 1 : 0;
}
return \@got;
});
#------------------------------------------------------------------------------
# A104488 -- num Hamiltonian groups
# No, different at n=67 and more
#
# MyOEIS::compare_values
# (anum => 'A104488',
# func => sub {
# my ($count) = @_;
# require Math::NumSeq::PlanePathTurn;
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'CCurve',
# turn_type => 'Right');
# my @got = (0,0,0,0);;
# while (@got < $count) {
# my ($i,$value) = $seq->next;
# push @got, $value;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A146559 - (i+1)^k is X+iY at N=2^k
# A009545 - Im
# A146559 X at N=2^k, being Re((i+1)^k)
# A009545 Y at N=2^k, being Im((i+1)^k)
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
MyOEIS::compare_values
(anum => 'A146559',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A009545',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003159 - ending even 0 bits, is turn left or right
MyOEIS::compare_values
(anum => 'A003159',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my $turn = path_n_turn($path,$n);
if ($turn == 1 || $turn == 3) { # left or right
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A036554 - ending odd 0 bits, is turn straight or reverse
MyOEIS::compare_values
(anum => 'A036554',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my $turn = path_n_turn($path,$n);
if ($turn == 0 || $turn == 2) { # straight or reverse
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A007814 - count low 0s, is turn right - 1
MyOEIS::compare_values
(anum => 'A007814',
fixup => sub {
my ($bvalues) = @_;
@$bvalues = map {$_ % 4} @$bvalues;
},
func => sub {
my ($count) = @_;
my @got;
my $total_turn = 0;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
push @got, (1 - path_n_turn($path,$n)) % 4; # negate to right
}
return \@got;
});
#------------------------------------------------------------------------------
# A000120 - count 1 bits total turn
MyOEIS::compare_values
(anum => 'A000120',
fixup => sub {
my ($bvalues) = @_;
@$bvalues = map {$_ % 4} @$bvalues;
},
func => sub {
my ($count) = @_;
my @got = (0);
my $total_turn = 0;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
$total_turn += path_n_turn($path,$n);
push @got, $total_turn % 4;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PyramidSpiral-oeis.t 0000644 0001750 0001750 00000007657 12136177277 017227 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A217295 Permutation of natural numbers arising from applying the walk of triangular horizontal-last spiral (defined in A214226) to the data of square spiral (e.g. A214526).
# A214227 -- sum of 4 neighbours horizontal-last
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PyramidSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A217013 - inverse permutation, SquareSpiral -> PyramidSpiral
# X,Y in SquareSpiral order, N of PyramidSpiral
MyOEIS::compare_values
(anum => 'A217013',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $pyramid = Math::PlanePath::PyramidSpiral->new;
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy($n);
($x,$y) = (-$y,$x); # rotate +90
push @got, $pyramid->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217294 - permutation PyramidSpiral -> SquareSpiral
# X,Y in PyramidSpiral order, N of SquareSpiral
# but A217294 conceived by square spiral going up and clockwise
# and pyramid spiral going left and clockwise
# which means rotate -90 here
MyOEIS::compare_values
(anum => 'A217294',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $pyramid = Math::PlanePath::PyramidSpiral->new;
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $pyramid->n_start; @got < $count; $n++) {
my ($x, $y) = $pyramid->n_to_xy($n);
($x,$y) = ($y,-$x); # rotate -90
push @got, $square->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A053615 -- distance to pronic is abs(X)
MyOEIS::compare_values
(anum => 'A053615',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PyramidSpiral->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, abs($x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A214250 -- sum of 8 neighbours N
MyOEIS::compare_values
(anum => 'A214250',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PyramidSpiral->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
+ $path->xy_to_n($x+1,$y+1)
+ $path->xy_to_n($x-1,$y-1)
+ $path->xy_to_n($x-1,$y+1)
+ $path->xy_to_n($x+1,$y-1)
);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/MultipleRings-oeis.t 0000644 0001750 0001750 00000003671 12167160676 017234 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::MultipleRings;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A090915 -- permutation X,-Y mirror across X axis
MyOEIS::compare_values
(anum => 'A090915',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::MultipleRings->new(step=>8);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x,$y) = ($x,-$y);
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002024 - n repeated n times, is step=1 Radius+1
MyOEIS::compare_values
(anum => 'A002024',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::MultipleRings->new(step=>1);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, $path->n_to_radius($n) + 1;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/TriangularHypot-oeis.t 0000644 0001750 0001750 00000060055 12136177277 017572 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Maybe?
# A033686 One ninth of theta series of A2[hole]^2.
use 5.004;
use strict;
use Test;
plan tests => 22;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min', 'max';
use Math::PlanePath::TriangularHypot;
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A005881 - theta of A2 centred on edge
# theta = num points of norm==n
# 4---------4 3,-1 = 3*3+3 = 12
# / \ / \ -3,-1 = 12
# / \ / \ 0, 2 = 0+3*2*2 = 12
# / \ / \
# / \ / \ 4,2 = 6*6+3*2*2 = 48
# 3---------2---------3 -4,2 = 48
# / \ / \ / \ 0,-4 = 0+3*4*4 = 48
# / \ / \ / \
# / \ / \ / \
# / \ / \ / \
# 3---------1----*----1---------3
# \ / \ / \ /
# \ / \ / \ /
# \ / \ / \ /
# \ / \ / \ /
# 3---------2---------3
# . . . . . . 5
#
# . . . . . 4
#
# . 4 . 4 . . 3
#
# . . . . . . . 2
#
# . 3 . 2 . 3 . . 1
#
# . . . . . . . . . <- Y=0
#
# . . . 1 o 1 . . . 3 -1
#
# . . . . . . . . . -2
#
# . . 3 . 2 . 3. . . . -3
#
# . . . . . . . . . -4
#
# . . 4 . 4 . . . -5
#
# . . . . - . . . . -6
#
# X=0 1 2 3 4 5 6 7
sub xy_is_tedge {
my ($x, $y) = @_;
return ($y % 2 == 0 && ($x+$y) % 4 == 2);
}
MyOEIS::compare_values
(anum => q{A005881},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 4;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_tedge($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 8;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A004016 - count of points at distance n
MyOEIS::compare_values
(anum => 'A004016',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new;
my @got;
my $prev_h = 0;
my $num = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $h = ($x*$x + 3*$y*$y) / 4;
# Same when rotate -45 as per POD notes.
# ($x,$y) = (($x+$y)/2,
# ($y-$x)/2);
# $h = $x*$x + $x*$y + $y*$y;
if ($h == $prev_h) {
$num++;
} else {
$got[$prev_h] = $num;
$num = 1;
$prev_h = $h;
}
}
$#got = $count-1; # trim
foreach my $got (@got) { $got ||= 0 } # pad, mutate array
return \@got;
});
# A002324 num points of norm n, which is X^2+3*Y^2=4n with "even" points here
# divide by 6 for 1/6 wedge
# cf A004016 = 6*A002324 except for A004016(0)=1 skipped
# cf A033687 = A002324(3n+1)
MyOEIS::compare_values
(anum => q{A002324},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start + 1; # excluding N=0
my $num = 0;
my $want_norm = 4;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/6;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A005929 - theta series hexagons midpoint of edge
# 2,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,2,0,0,0,0,0,4,0,
# . . . . . . 5
#
# . 3 . 3 . 4
#
# . . . . . . 3
#
# . 2 . . . 2 . 2
#
# . . . . . . . . 1
#
# . . . 1 o 1 . . . <- Y=0
#
# . . . . . . . . . . -1
#
# . . 2 . . . 2 . . -2
#
# . . . . . . . . . . -3
#
# . . . 3 . 3 . . . -4
#
# . . . . . . . . -5
#
# . . . . - . . . . -6
#
# 2 = 4*4+3*2*2 = 28
# 3 = 2*2+3*4*4 = 52
sub xy_is_hexedge {
my ($x, $y) = @_;
my $k = $x + 3*$y;
return ($y % 2 == 0 && ($k % 12 == 2 || $k % 12 == 10));
}
# foreach my $y (0 .. 20) {
# foreach my $x (0 .. 60) {
# print xy_is_hexedge($x,$y) ? '*' : ' ';
# }
# print "\n";
# }
MyOEIS::compare_values
(anum => q{A005929},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got = (0);
my $n = $path->n_start;
my $num = 0;
my $want_norm = 4;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_hexedge($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
# A045839 = A005929/2.
MyOEIS::compare_values
(anum => q{A045839},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got = (0);
my $n = $path->n_start;
my $num = 0;
my $want_norm = 4;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_hexedge($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/2;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A038588 - clusters A2 centred deep hole
# 3, 6, 12, 18, 21, 27 ...
# unique values from A038587 = 3,6,12,12,18,21,27,27,30,
# which is partial sums A005882 theta relative hole,
# = 3,3,6,0,6,3,6,0,3,6,6,0,6,0,6,0,9,6,0,0,6
# theta = num points of norm==n
# 3---------3 3,-1 = 3*3+3 = 12
# / \ / \ -3,-1 = 12
# / \ / \ 0, 2 = 0+3*2*2 = 12
# / \ / \
# / \ / \ 4,2 = 6*6+3*2*2 = 48
# 2---------1---------2 -4,2 = 48
# / \ / \ / \ 0,-4 = 0+3*4*4 = 48
# / \ / \ / \
# / \ / * \ / \
# / \ / \ / \
# 3---------1---------1---------3
# \ / \ / \ /
# \ / \ / \ /
# \ / \ / \ /
# \ / \ / \ /
# 3---------2---------3
# . 3 . . 3 . 5
#
# . . . . . 4
#
# . . . . . . 3
#
# 2 . . 1 . . 2 2
#
# . . . . . . . . 1
#
# . . . . o . . . . <- Y=0
#
# 3 . . 1 . . 1 . . 3 -1
#
# . . . . . . . . . -2
#
# . . . . . . . . . . -3
#
# . 3 . . 2 . . 3 . -4
#
# . . . . . . . . -5
#
# . . . . - . . . . -6
# X=0 1 2 3 4 5 6 7
#
# X+Y=6k+2
# Y=3z+2
#
# block X mod 6, Y mod 6 only X=0,Y=2 and X=3,Y=5
# X+6Y mod 36 = 2*6=12 or 3+6*5=33 cf -3+6*-1=-9=
# shift down X=0,Y=0 X=3,Y=3 only
# X+6Y mod 36 = 0 or 3+6*3=21
#
# X=6k
# also rotate +120 -(X+3Y)/2 = 6k is X+3Y = 12k
# also rotate -120 (3Y-X)/2 = 6k is X-3Y = 12k
sub xy_is_tcentred {
my ($x, $y) = @_;
return ($y % 3 == 2 &&($x+$y) % 6 == 2);
# Wrong:
# my $k = ($x + 6*$y) % 36;
# return ($k == 0+6*2 || $k == 3+6*5);
}
# A033687 with zeros, full steps of norm, divide by 3
# cf A033687 = A002324(3n+1)
# A033687 = A005882 / 3
# A033687 = A033685(3n+1)
MyOEIS::compare_values
(anum => q{A033687},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 12;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_tcentred($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/3;
$want_norm += 36;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
# 0, 3, 0, 0, 3, 0, 0, 6, 0, 0, 0, 0, 0, 6, 0, 0, 3, 0, 0, 6, 0, 0, 0, 0,
# 1, 1, 2, 0, 2, 1, 2, 0, 1, 2, 2, 0, 2, 0, 2, 0, 3, 2, 0, 0, 2, 1, 2, 0,
# A033687 Theta series of hexagonal lattice A_2 with respect to deep hole.
MyOEIS::compare_values
(anum => q{A038588}, # no duplicates
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 12;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + 3*$y*$y;
if (! xy_is_tcentred($x,$y)) {
### sk: "$n at $x,$y norm=$norm"
$n++;
next;
}
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm = $norm;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$num++;
$n++;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A038587}, # with duplicates
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 12;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_tcentred($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 36;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$num++;
$n++;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A005882}, # with zeros
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 12;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_tcentred($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 36;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A033685}, # with zeros, 1/3 steps of norm
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got = (0);
my $n = $path->n_start;
my $num = 0;
my $want_norm = 12;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_tcentred($x,$y)) {
$n++;
next;
}
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 12;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A217219 - theta of honeycomb at centre hole
# count of how many at norm=4*k, possibly zero
MyOEIS::compare_values
(anum => 'A217219',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new(points=>'hex_centred');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 0;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A113062 - theta of honeycomb at node,
# count of how many at norm=4*k, possibly zero
MyOEIS::compare_values
(anum => 'A113062',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'hex');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 0;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A113063', # divided by 3
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'hex');
my @got;
my $n = $path->n_start + 1; # excluding origin X=0,Y=0
my $num = 0;
my $want_norm = 4;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + 3*$y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/3;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A014201 - number of solutions x^2+xy+y^2 <= n excluding 0,0
#
# norm = x^2+x*y+y^2 <= n
# = (X^2 + 3*Y^2) / 4 <= n
# = X^2 + 3*Y^2 <= 4*n
MyOEIS::compare_values
(anum => 'A014201',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $num = 0;
my $want_norm = 0;
my $n = $path->n_start + 1; # skip X=0,Y=0 at N=Nstart
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
($x,$y) = (($y-$x)/2, ($x+$y)/2);
my $norm = $x*$x + $x*$y + $y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm++;
} else {
$num++;
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A038589 - number of solutions x^2+xy+y^2 <= n including 0,0
# - sizes successive clusters A2 centred at lattice point
MyOEIS::compare_values
(anum => 'A038589',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'even');
my @got;
my $num = 0;
my $want_norm = 0;
my $n = $path->n_start;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
($x,$y) = (($y-$x)/2, ($x+$y)/2);
my $norm = $x*$x + $x*$y + $y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm++;
} else {
$num++;
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A092572 - all X^2+3Y^2 values which occur, points="all" X>0,Y>0
MyOEIS::compare_values
(anum => 'A092572',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'all');
my @got;
my $prev_h = -1;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
next unless ($x > 0 && $y > 0);
my $h = $x*$x + 3*$y*$y;
if ($h != $prev_h) {
push @got, $h;
$prev_h = $h;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A158937 - all X^2+3Y^2 values which occur, points="all" X>0,Y>0, with repeats
MyOEIS::compare_values
(anum => 'A158937',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'all');
my @got;
my $prev_h = -1;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
next unless ($x > 0 && $y > 0);
my $h = $x*$x + 3*$y*$y;
push @got, $h;
}
return \@got;
});
#------------------------------------------------------------------------------
# A092573 - count of points at distance n, points="all" X>0,Y>0
MyOEIS::compare_values
(anum => 'A092573',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'all');
my @got;
my $prev_h = 0;
my $num = 0;
for (my $n = $path->n_start; @got+1 < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
next unless ($x > 0 && $y > 0);
my $h = $x*$x + 3*$y*$y;
if ($h == $prev_h) {
$num++;
} else {
$got[$prev_h] = $num;
$num = 1;
$prev_h = $h;
}
}
shift @got; # drop n=0, start from n=1
$#got = $count-1; # trim
foreach my $got (@got) { $got ||= 0 } # pad, mutate array
return \@got;
});
#------------------------------------------------------------------------------
# A092574 - all X^2+3Y^2 values which occur, points="all" X>0,Y>0 gcd(X,Y)=1
MyOEIS::compare_values
(anum => 'A092574',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'all');
my @got;
my $prev_h = -1;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
next unless ($x > 0 && $y > 0);
next unless gcd($x,$y) == 1;
my $h = $x*$x + 3*$y*$y;
if ($h != $prev_h) {
push @got, $h;
$prev_h = $h;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A092575 - count of points at distance n, points="all" X>0,Y>0 gcd(X,Y)=1
MyOEIS::compare_values
(anum => 'A092575',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new (points => 'all');
my @got;
my $prev_h = 0;
my $num = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
next unless ($x > 0 && $y > 0);
next unless gcd($x,$y) == 1;
my $h = $x*$x + 3*$y*$y;
if ($h == $prev_h) {
$num++;
} else {
$got[$prev_h] = $num;
$num = 1;
$prev_h = $h;
}
}
shift @got; # drop n=0, start from n=1
$#got = $count-1; # trim
foreach my $got (@got) { $got ||= 0 } # pad, mutate array
return \@got;
});
sub gcd {
my ($x, $y) = @_;
#### _gcd(): "$x,$y"
if ($y > $x) {
$y %= $x;
}
for (;;) {
if ($y <= 1) {
return ($y == 0 ? $x : 1);
}
($x,$y) = ($y, $x % $y);
}
}
#------------------------------------------------------------------------------
# A088534 - count of points 0<=x<=y, points="even"
MyOEIS::compare_values
(anum => 'A088534',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new;
my @got = (0) x scalar($count);
my $prev_h = 0;
my $num = 0;
for (my $n = $path->n_start; ; $n++) {
my ($x,$y) = $path->n_to_xy($n);
# next unless 0 <= $x && $x <= $y;
next unless 0 <= $y && $y <= $x/3;
my $h = ($x*$x + 3*$y*$y) / 4;
# Same when rotate -45 as per POD notes.
# ($x,$y) = (($x+$y)/2,
# ($y-$x)/2);
# $h = $x*$x + $x*$y + $y*$y;
if ($h == $prev_h) {
$num++;
} else {
last if $prev_h >= $count;
$got[$prev_h] = $num;
$num = 1;
$prev_h = $h;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A003136 - Loeschian numbers, norms of A2 lattice
MyOEIS::compare_values
(anum => 'A003136',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new;
my @got;
my $prev_h = -1;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $h = ($x*$x + 3*$y*$y) / 4;
if ($h != $prev_h) {
push @got, $h;
$prev_h = $h;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A035019 - count of each hypot distance
MyOEIS::compare_values
(anum => 'A035019',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangularHypot->new;
my @got;
my $prev_h = 0;
my $num = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + 3*$y*$y;
if ($h == $prev_h) {
$num++;
} else {
push @got, $num;
$num = 1;
$prev_h = $h;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/GosperSide-oeis.t 0000644 0001750 0001750 00000021571 12207311305 016457 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::GosperSide;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $path = Math::PlanePath::GosperSide->new;
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
my %dxdy_to_dir = ('2,0' => 0,
'1,1' => 1,
'-1,1' => 2,
'-2,0' => 3,
'-1,-1' => 4,
'1,-1' => 5);
# return 0 if X,Y's are straight, 2 if left, 1 if right
sub xy_turn_6 {
my ($prev_x,$prev_y, $x,$y, $next_x,$next_y) = @_;
my $prev_dx = $x - $prev_x;
my $prev_dy = $y - $prev_y;
my $dx = $next_x - $x;
my $dy = $next_y - $y;
my $prev_dir = $dxdy_to_dir{"$prev_dx,$prev_dy"};
if (! defined $prev_dir) { die "oops, unrecognised $prev_dx,$prev_dy"; }
my $dir = $dxdy_to_dir{"$dx,$dy"};
if (! defined $dir) { die "oops, unrecognised $dx,$dy"; }
return ($dir - $prev_dir) % 6;
}
# 0=left, 1=right
sub xy_left_right {
my ($prev_x,$prev_y, $x,$y, $next_x,$next_y) = @_;
my $turn = xy_turn_6 ($prev_x,$prev_y, $x,$y, $next_x,$next_y);
if ($turn == 1) {
return 0; # left;
}
if ($turn == 5) {
return 1; # right;
}
die "unrecognised turn $turn";
}
#------------------------------------------------------------------------------
# A189673 - morphism turn 0=left, 1=right, extra initial 0
MyOEIS::compare_values
(anum => 'A189673',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Left');
my @got = (0);
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A189640 - morphism turn 0=left, 1=right, extra initial 0
MyOEIS::compare_values
(anum => 'A189640',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my @got = (0);
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A060032 - turn 1=left, 2=right as bignums to 3^level
{
my $anum = 'A060032';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $level = 0; @got < @$bvalues; $level++) {
require Math::BigInt;
my $big = Math::BigInt->new(0);
foreach my $n (1 .. 3**$level) {
my $digit = xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1)) + 1;
$big = 10*$big + $digit;
}
push @got, $big;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - 0,1 turns");
}
#------------------------------------------------------------------------------
# A062756 - ternary count 1s, is cumulative turn
{
my $anum = 'A062756';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative;
push @got, 0; # bvalues starts with an n=0
for (my $n = $path->n_start + 1; @got < @$bvalues; $n++) {
my $turn = xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1));
$cumulative += ($turn == 0 ? 1 : -1);
push @got, $cumulative;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - cumulative turn");
}
#------------------------------------------------------------------------------
# A080846 - turn 0=left, 1=right
{
my $anum = 'A080846';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = $path->n_start + 1; @got < @$bvalues; $n++) {
push @got, xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1));
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - turn 0=left,1=right");
}
#------------------------------------------------------------------------------
# A038502 - taken mod 3 is 1=left, 2=right
{
my $anum = 'A038502';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
@$bvalues = map { $_ % 3 } @$bvalues;
for (my $n = $path->n_start + 1; @got < @$bvalues; $n++) {
push @got, xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1)) + 1;
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - taken mod 3 for 0,1 turns");
}
#------------------------------------------------------------------------------
# A026225 - positions of left turns
{
my $anum = 'A026225';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my @got;
if ($bvalues) {
for (my $n = $path->n_start + 1; @got < @$bvalues; $n++) {
if (xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1))
== 0) {
push @got, $n;
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - left turns");
}
{
my @got;
if ($bvalues) {
for (my $n = 1; @got < @$bvalues; $n++) {
if (digit_above_low_zeros($n) == 1) {
push @got, $n;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - N where lowest non-zero 1");
}
}
#------------------------------------------------------------------------------
# A026179 - positions of right turns
{
my $anum = 'A026179';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
{
my @got;
if ($bvalues) {
push @got, 1; # extra 1 ...
for (my $n = $path->n_start + 1; @got < @$bvalues; $n++) {
if (xy_left_right ($path->n_to_xy($n-1),
$path->n_to_xy($n),
$path->n_to_xy($n+1))
== 1) {
push @got, $n;
}
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - right turns");
}
{
my @got = (1);
if ($bvalues) {
for (my $n = 1; @got < @$bvalues; $n++) {
if (digit_above_low_zeros($n) == 2) {
push @got, $n;
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - N where lowest non-zero 2");
}
}
sub digit_above_low_zeros {
my ($n) = @_;
if ($n == 0) {
return 0;
}
while (($n % 3) == 0) {
$n = int($n/3);
}
return ($n % 3);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/QuadricCurve-oeis.t 0000644 0001750 0001750 00000003113 12153211070 016776 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::QuadricCurve;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A133851 -- Y at N=2^k is 2^(k/4) when k=0mod4, starting
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
MyOEIS::compare_values
(anum => 'A133851',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::QuadricCurve->new;
my @got;
for (my $n = $bigclass->new(2); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/AnvilSpiral-oeis.t 0000644 0001750 0001750 00000003540 12136177303 016644 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::AnvilSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A033581 - N on Y axis (6*n^2) except for initial N=2
MyOEIS::compare_values
(anum => 'A033581',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::AnvilSpiral->new (wider => 2);
my @got = (0);
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A136392 - N on Y negative, with offset making n=-Y+1
MyOEIS::compare_values
(anum => 'A136392',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::AnvilSpiral->new;
my @got;
for (my $y = 0; @got < $count; $y--) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/CellularRule-oeis.t 0000644 0001750 0001750 00000065154 12136177302 017023 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# cf A094605 rule 30 period of nth diagonal
# A094606 log2 of that period
#
use 5.004;
use strict;
use Test;
plan tests => 199;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::CellularRule;
# uncomment this to run the ### lines
#use Smart::Comments '###';
MyTestHelpers::diag ("OEIS dir ",MyOEIS::oeis_dir());
sub streq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
while (@$a1 && @$a2) {
if ($a1->[0] ne $a2->[0]) {
MyTestHelpers::diag ("differ: ", $a1->[0], ' ', $a2->[0]);
return 0;
}
shift @$a1;
shift @$a2;
}
return (@$a1 == @$a2);
}
#------------------------------------------------------------------------------
foreach my $elem
(
[ 'A071022', 70, 'bits', 'left' ],
[ 'A071022', 198, 'bits', 'left' ],
[ 'A071023', 78, 'bits', 'left' ],
[ 'A071024', 92, 'bits', 'right' ],
[ 'A071025', 124, 'bits', 'right' ],
[ 'A071026', 188, 'bits', 'right' ],
[ 'A071027', 230, 'bits', 'left' ],
[ 'A071028', 50, 'bits' ],
[ 'A071029', 22, 'bits' ],
[ 'A071030', 54, 'bits' ],
[ 'A071031', 62, 'bits' ],
[ 'A071032', 86, 'bits' ],
[ 'A071033', 94, 'bits' ],
[ 'A071034', 118, 'bits' ],
[ 'A071035', 126, 'bits' ],
[ 'A071036', 150, 'bits' ], # same as A118110
[ 'A071037', 158, 'bits' ],
[ 'A071038', 182, 'bits' ],
[ 'A071039', 190, 'bits' ],
[ 'A071040', 214, 'bits' ],
[ 'A071041', 246, 'bits' ],
# [ 'A060576', 255, 'bits' ], # homeomorphically irreducibles ...
[ 'A070909', 28, 'bits', 'right' ],
[ 'A070909', 156, 'bits', 'right' ],
[ 'A075437', 110, 'bits' ],
[ 'A118101', 94, 'bignum' ],
[ 'A118102', 94, 'bits' ],
[ 'A118108', 54, 'bignum' ],
[ 'A118109', 54, 'bits' ],
[ 'A118110', 150, 'bits' ],
[ 'A118111', 190, 'bits' ],
[ 'A118171', 158, 'bignum' ],
[ 'A118172', 158, 'bits' ],
[ 'A118173', 188, 'bignum' ],
[ 'A118174', 188, 'bits' ],
[ 'A118175', 220, 'bits' ],
[ 'A118175', 252, 'bits' ],
[ 'A070887', 110, 'bits', 'left' ],
[ 'A071042', 90, 'number_of', 0 ],
[ 'A071043', 22, 'number_of', 0 ],
[ 'A071044', 22, 'number_of', 1 ],
[ 'A071045', 54, 'number_of', 0 ],
[ 'A071046', 62, 'number_of', 0 ],
[ 'A071047', 62, 'number_of', 1 ],
[ 'A071049', 110, 'number_of', 1 ],
[ 'A071048', 110, 'number_of', 0, 'left' ],
[ 'A071050', 126, 'number_of', 0 ],
[ 'A071051', 126, 'number_of', 1 ],
[ 'A071052', 150, 'number_of', 0 ],
[ 'A071053', 150, 'number_of', 1 ],
[ 'A071054', 158, 'number_of', 1 ],
[ 'A071055', 182, 'number_of', 0 ],
[ 'A038184', 150, 'bignum' ],
[ 'A038185', 150, 'bignum', 'left' ], # cut after central column
[ 'A001045', 28, 'bignum' ], # Jacobsthal
[ 'A110240', 30, 'bignum' ], # cf A074890 some strange form
[ 'A117998', 102, 'bignum' ],
[ 'A117999', 110, 'bignum' ],
[ 'A037576', 190, 'bignum' ],
[ 'A002450', 250, 'bignum' ],
[ 'A006977', 230, 'bignum', 'left' ],
[ 'A078176', 225, 'bignum', 'whole', 'inverse' ],
[ 'A051023', 30, 'bits', 'centre' ],
[ 'A070950', 30, 'bits' ],
[ 'A070951', 30, 'number_of', 0 ],
[ 'A070952', 30, 'number_of', 1 ],
[ 'A151929', 30, 'number_of_1s_first_diff' ],
[ 'A092539', 30, 'bignum_central_column' ],
[ 'A094603', 30, 'trailing_number_of', 1 ],
[ 'A094604', 30, 'new_maximum_trailing_number_of', 1 ],
[ 'A001316', 90, 'number_of', 1 ], # Gould's sequence
#--------------------------------------------------------------------------
# Sierpinski triangle, 8 of whole
# rule=60 right half
[ 'A047999', 60, 'bits', 'right' ], # Sierpinski triangle in right
[ 'A001317', 60, 'bignum' ], # Sierpinski triangle right half
[ 'A075438', 60, 'bits' ], # including 0s in left half
# rule=102 left half
[ 'A047999', 102, 'bits', 'left' ],
[ 'A075439', 102, 'bits' ],
[ 'A038183', 18, 'bignum' ], # Sierpinski bignums
[ 'A038183', 26, 'bignum' ],
[ 'A038183', 82, 'bignum' ],
[ 'A038183', 90, 'bignum' ],
[ 'A038183', 146, 'bignum' ],
[ 'A038183', 154, 'bignum' ],
[ 'A038183', 210, 'bignum' ],
[ 'A038183', 218, 'bignum' ],
[ 'A070886', 18, 'bits' ], # Sierpinski 0/1
[ 'A070886', 26, 'bits' ],
[ 'A070886', 82, 'bits' ],
[ 'A070886', 90, 'bits' ],
[ 'A070886', 146, 'bits' ],
[ 'A070886', 154, 'bits' ],
[ 'A070886', 210, 'bits' ],
[ 'A070886', 218, 'bits' ],
#--------------------------------------------------------------------------
# simple stuff
# whole solid, values 2^(2n)-1
[ 'A083420', 151, 'bignum' ], # 8 of
[ 'A083420', 159, 'bignum' ],
[ 'A083420', 183, 'bignum' ],
[ 'A083420', 191, 'bignum' ],
[ 'A083420', 215, 'bignum' ],
[ 'A083420', 223, 'bignum' ],
[ 'A083420', 247, 'bignum' ],
[ 'A083420', 254, 'bignum' ],
# and also
[ 'A083420', 222, 'bignum' ], # 2 of
[ 'A083420', 255, 'bignum' ],
# right half solid 2^n-1
[ 'A000225', 220, 'bignum' ],
[ 'A000225', 252, 'bignum' ],
# left half solid, # 2^n-1
[ 'A000225', 206, 'bignum', 'left' ], # 0xCE
[ 'A000225', 238, 'bignum', 'left' ], # 0xEE
# central column only, values all 1s
[ 'A000012', 4, 'bignum', 'left' ],
[ 'A000012', 12, 'bignum', 'left' ],
[ 'A000012', 36, 'bignum', 'left' ],
[ 'A000012', 44, 'bignum', 'left' ],
[ 'A000012', 68, 'bignum', 'left' ],
[ 'A000012', 76, 'bignum', 'left' ],
[ 'A000012', 100, 'bignum', 'left' ],
[ 'A000012', 108, 'bignum', 'left' ],
[ 'A000012', 132, 'bignum', 'left' ],
[ 'A000012', 140, 'bignum', 'left' ],
[ 'A000012', 164, 'bignum', 'left' ],
[ 'A000012', 172, 'bignum', 'left' ],
[ 'A000012', 196, 'bignum', 'left' ],
[ 'A000012', 204, 'bignum', 'left' ],
[ 'A000012', 228, 'bignum', 'left' ],
[ 'A000012', 236, 'bignum', 'left' ],
#
# central column only, central values N=1,2,3,etc all integers
[ 'A000027', 4, 'central_column_N' ],
[ 'A000027', 12, 'central_column_N' ],
[ 'A000027', 36, 'central_column_N' ],
[ 'A000027', 44, 'central_column_N' ],
[ 'A000027', 76, 'central_column_N' ],
[ 'A000027', 108, 'central_column_N' ],
[ 'A000027', 132, 'central_column_N' ],
[ 'A000027', 140, 'central_column_N' ],
[ 'A000027', 164, 'central_column_N' ],
[ 'A000027', 172, 'central_column_N' ],
[ 'A000027', 196, 'central_column_N' ],
[ 'A000027', 204, 'central_column_N' ],
[ 'A000027', 228, 'central_column_N' ],
[ 'A000027', 236, 'central_column_N' ],
#
# central column only, values 2^k
[ 'A000079', 4, 'bignum' ],
[ 'A000079', 12, 'bignum' ],
[ 'A000079', 36, 'bignum' ],
[ 'A000079', 44, 'bignum' ],
[ 'A000079', 68, 'bignum' ],
[ 'A000079', 76, 'bignum' ],
[ 'A000079', 100, 'bignum' ],
[ 'A000079', 108, 'bignum' ],
[ 'A000079', 132, 'bignum' ],
[ 'A000079', 140, 'bignum' ],
[ 'A000079', 164, 'bignum' ],
[ 'A000079', 172, 'bignum' ],
[ 'A000079', 196, 'bignum' ],
[ 'A000079', 204, 'bignum' ],
[ 'A000079', 228, 'bignum' ],
[ 'A000079', 236, 'bignum' ],
# right diagonal only, values all 1, 16 of
[ 'A000012', 0x10, 'bignum' ],
[ 'A000012', 0x18, 'bignum' ],
[ 'A000012', 0x30, 'bignum' ],
[ 'A000012', 0x38, 'bignum' ],
[ 'A000012', 0x50, 'bignum' ],
[ 'A000012', 0x58, 'bignum' ],
[ 'A000012', 0x70, 'bignum' ],
[ 'A000012', 0x78, 'bignum' ],
[ 'A000012', 0x90, 'bignum' ],
[ 'A000012', 0x98, 'bignum' ],
[ 'A000012', 0xB0, 'bignum' ],
[ 'A000012', 0xB8, 'bignum' ],
[ 'A000012', 0xD0, 'bignum' ],
[ 'A000012', 0xD8, 'bignum' ],
[ 'A000012', 0xF0, 'bignum' ],
[ 'A000012', 0xF8, 'bignum' ],
# left diagonal only, values 2^k
[ 'A000079', 0x02, 'bignum', 'left' ],
[ 'A000079', 0x0A, 'bignum', 'left' ],
[ 'A000079', 0x22, 'bignum', 'left' ],
[ 'A000079', 0x2A, 'bignum', 'left' ],
[ 'A000079', 0x42, 'bignum', 'left' ],
[ 'A000079', 0x4A, 'bignum', 'left' ],
[ 'A000079', 0x62, 'bignum', 'left' ],
[ 'A000079', 0x6A, 'bignum', 'left' ],
[ 'A000079', 0x82, 'bignum', 'left' ],
[ 'A000079', 0x8A, 'bignum', 'left' ],
[ 'A000079', 0xA2, 'bignum', 'left' ],
[ 'A000079', 0xAA, 'bignum', 'left' ],
[ 'A000079', 0xC2, 'bignum', 'left' ],
[ 'A000079', 0xCA, 'bignum', 'left' ],
[ 'A000079', 0xE2, 'bignum', 'left' ],
[ 'A000079', 0xEA, 'bignum', 'left' ],
# bits, characteristic of square
[ 'A010052', 0x02, 'bits' ],
[ 'A010052', 0x0A, 'bits' ],
[ 'A010052', 0x22, 'bits' ],
[ 'A010052', 0x2A, 'bits' ],
[ 'A010052', 0x42, 'bits' ],
[ 'A010052', 0x4A, 'bits' ],
[ 'A010052', 0x62, 'bits' ],
[ 'A010052', 0x6A, 'bits' ],
[ 'A010052', 0x82, 'bits' ],
[ 'A010052', 0x8A, 'bits' ],
[ 'A010052', 0xA2, 'bits' ],
[ 'A010052', 0xAA, 'bits' ],
[ 'A010052', 0xC2, 'bits' ],
[ 'A010052', 0xCA, 'bits' ],
[ 'A010052', 0xE2, 'bits' ],
[ 'A010052', 0xEA, 'bits' ],
) {
### $elem
my ($anum, $rule, $method, @params) = @$elem;
my $func = main->can($method) || die "Unrecognised method $method";
&$func ($anum, $rule, @params);
}
#------------------------------------------------------------------------------
# number of 0s or 1s in row
sub number_of {
my ($anum, $rule, $want_value, $half) = @_;
$half ||= 'whole';
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my $max_count;
if ($anum eq 'A070952') {
$max_count = 400; # shorten
}
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum number_of");
if ($anum eq 'A071049') { # extra initial 0
push @got, 0;
}
if ($anum eq 'A070952') { # extra initial 0
push @got, 0;
}
for (my $y = 0; @got < @$bvalues; $y++) {
my $count = 0;
foreach my $x (($half eq 'right' || $half eq 'centre' ? 0 : -$y)
.. ($half eq 'left' || $half eq 'centre' ? 0 : $y)) {
my $n = $path->xy_to_n ($x, $y);
my $got_value = (defined $n ? 1 : 0);
if ($got_value == $want_value) {
$count++;
}
}
push @got, $count;
}
if (! streq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum number of ${want_value}s in rows rule $rule, $half");
}
sub number_of_1s_first_diff {
my ($anum, $rule) = @_;
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my $max_count;
if ($anum eq 'A151929') {
$max_count = 400; # shorten
}
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum number_of first diffs");
my $prev_count = 0;
for (my $y = 0; @got < @$bvalues; $y++) {
my $count = 0;
foreach my $x (-$y .. $y) {
if ($path->xy_to_n ($x, $y)) {
$count++;
}
}
push @got, $count - $prev_count;
$prev_count = $count;
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum number of 1s first differences");
}
#------------------------------------------------------------------------------
# number of 0s or 1s in row at the rightmost end
sub trailing_number_of {
my ($anum, $rule, $want_value) = @_;
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum trailing_number_of");
for (my $y = 0; @got < @$bvalues; $y++) {
my $count = 0;
for (my $x = $y; $x >= -$y; $x--) {
my $n = $path->xy_to_n ($x, $y);
my $got_value = (defined $n ? 1 : 0);
if ($got_value == $want_value) {
$count++;
} else {
last;
}
}
push @got, $count;
}
if (! streq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum trailing number of ${want_value}s in rows rule $rule");
}
sub new_maximum_trailing_number_of {
my ($anum, $rule, $want_value) = @_;
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum new_maximum_trailing_number_of");
if ($anum eq 'A094604') {
# new max only at Y=2^k, so limit search
if ($#$bvalues > 10) {
$#$bvalues = 10;
}
}
my $prev = 0;
for (my $y = 0; @got < @$bvalues; $y++) {
my $count = 0;
for (my $x = $y; $x >= -$y; $x--) {
my $n = $path->xy_to_n ($x, $y);
my $got_value = (defined $n ? 1 : 0);
if ($got_value == $want_value) {
$count++;
} else {
last;
}
}
if ($count > $prev) {
push @got, $count;
$prev = $count;
}
}
if (! streq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum");
}
#------------------------------------------------------------------------------
# bignum rows
sub bignum {
my ($anum, $rule, $half, $inverse) = @_;
$half ||= 'whole';
$inverse ||= ''; # 'inverse' for bitwise invert
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
### $path
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum bignum");
my $y_start = 0;
if ($anum eq 'A078176') { # no initial 0 for row 0
$y_start = 1;
}
if ($anum eq 'A000012') { # trim all-ones
if ($#$bvalues > 50) { $#$bvalues = 50; }
}
if ($anum eq 'A001045') { # Jacobsthal extra 0,1
push @got, 0,1;
}
if ($anum eq 'A002450') { # (4^n-1)/3 10101 extra 0 at start
push @got, 0;
}
if ($anum eq 'A000225') { # 2^n-1 want start from 1
push @got, 0;
}
require Math::BigInt;
for (my $y = $y_start; @got < @$bvalues; $y++) {
my $b = Math::BigInt->new(0);
foreach my $x (($half eq 'right' ? 0 : -$y)
.. ($half eq 'left' ? 0 : $y)) {
my $bit = ($path->xy_is_visited($x,$y) ? 1 : 0);
if ($inverse eq 'inverse') { $bit ^= 1; }
$b = 2*$b + $bit;
}
push @got, "$b";
}
if (! streq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum bignums $half");
}
#------------------------------------------------------------------------------
# 0/1 by rows
sub bits {
my ($anum, $rule, $half) = @_;
### bits(): @_
$half ||= 'whole';
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum bits");
OUTER: for (my $y = 0; ; $y++) {
foreach my $x (($half eq 'right' || $half eq 'centre' ? 0 : -$y)
.. ($half eq 'left' || $half eq 'centre' ? 0 : $y)) {
last OUTER if @got >= @$bvalues;
push @got, ($path->xy_to_n ($x, $y) ? 1 : 0);
}
}
if (! streq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum 0/1 rows rule $rule, $half");
}
#------------------------------------------------------------------------------
# bignum central vertical column
sub bignum_central_column {
my ($anum, $rule) = @_;
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum central column bignum");
require Math::BigInt;
my $b = Math::BigInt->new(0);
for (my $y = 0; @got < @$bvalues; $y++) {
my $bit = ($path->xy_to_n (0, $y) ? 1 : 0);
$b = 2*$b + $bit;
push @got, "$b";
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum");
}
#------------------------------------------------------------------------------
# N values of central vertical column
sub central_column_N {
my ($anum, $rule) = @_;
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
MyTestHelpers::diag ("$anum central column N");
for (my $y = 0; @got < @$bvalues; $y++) {
push @got, $path->xy_to_n (0, $y);
}
}
skip (! $bvalues,
streq_array(\@got, $bvalues),
1, "$anum");
}
#------------------------------------------------------------------------------
# A071029 rule 22 ... ?
#
# 22 = 00010110
# 111 -> 0
# 110 -> 0
# 101 -> 0
# 100 -> 1
# 011 -> 0
# 010 -> 1
# 001 -> 1
# 000 -> 0
# 0,
# 1, 0, 1,
# 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
# 0,
# 1,
# 0, 1, 0,
# 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0, 1,
# 0
# A071043 Number of 0's in n-th row of triangle in A071029.
# 0, 0, 3, 1, 7, 5, 9, 3, 15, 13, 17, 11, 21, 15, 21, 7, 31, 29, 33, 27,
# 37, 31, 37, 23, 45, 39, 45, 31, 49, 35, 45, 15, 63, 61, 65, 59, 69, 63,
# 69, 55, 77, 71, 77, 63, 81, 67, 77, 47, 93, 87, 93, 79, 97, 83, 93, 63,
# 105, 91, 101, 71, 105, 75, 93, 31, 127, 125, 129
#
# A071044 Number of 1's in n-th row of triangle in A071029.
# 1, 3, 2, 6, 2, 6, 4, 12, 2, 6, 4, 12, 4, 12, 8, 24, 2, 6, 4, 12, 4, 12,
# 8, 24, 4, 12, 8, 24, 8, 24, 16, 48, 2, 6, 4, 12, 4, 12, 8, 24, 4, 12,
# 8, 24, 8, 24, 16, 48, 4, 12, 8, 24, 8, 24, 16, 48, 8, 24, 16, 48, 16,
# 48, 32, 96, 2, 6, 4, 12, 4, 12, 8, 24, 4, 12, 8, 24, 8, 24, 16, 48
#
# *** *** *** ***
# * * * *
# *** ***
# * *
# *** ***
# * *
# ***
# *
#------------------------------------------------------------------------------
# A071026 rule 188
# rows n+1
#
# 1,
# 1, 0,
# 0, 1, 1,
# 0, 1, 0, 1,
# 1, 1, 1, 1, 0,
# 0, 0, 1, 1, 0, 1,
# 1, 1, 1, 1, 1, 1, 1,
# 1, 0, 1, 1, 0, 0, 1, 1,
# 1, 1, 0, 0, 0, 0, 0, 0, 1,
# 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
# 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1,
# 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0,
# 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0,
# 0, 1, 1, 1, 0, 1, 1, 0
#
# * *** *
# ** ***
# *** *
# ****
# * *
# **
# *
#------------------------------------------------------------------------------
# A071023 rule 78
# *** * * *
# ** * * *
# *** * *
# ** * *
# *** *
# ** *
# ***
# **
# *
# 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 0, 1, 1, 1, 1,
# 0, 1, 1, 1,
# 0, 1, 0,
# 1, 1, 1
# 111 ->
# 110 ->
# 101 ->
# 100 ->
# 011 ->
# 010 -> 1
# 001 -> 1
# 000 ->
# 1,
# 1, 1,
# 0, 1, 0,
# 1, 0, 1, 0,
# 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 1, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1,
# 1, 1, 0, 1, 0, 1, 1, 1
#------------------------------------------------------------------------------
# A071024 rule 92
# 0, 1, 0, 1, 0,
# 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
#------------------------------------------------------------------------------
# A071027 rule 230
# * *** *** *
# *** *** **
# * *** ***
# *** ****
# * *** *
# *** **
# * ***
# ****
# * *
# **
# *
# 1, 1, 1, 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 1, 1, 0,
# 1
#------------------------------------------------------------------------------
# # A071035 rule 126 sierpinski
#
# 1,
# 1, 0, 1,
# 1, 0, 1,
# 1, 0, 0, 0, 1,
# 1, 1, 1, 0, 1, 0, 1, 1, 1,
# 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
# 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
# 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1,
# 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0
#------------------------------------------------------------------------------
# A071022 rule 70,198
# ** * * * *
# * * * * *
# ** * * *
# * * * *
# ** * *
# * * *
# ** *
# * *
# **
# *
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 1, 1, 1, 1, 0,
# 1, 1, 1, 0,
# 1, 1, 0,
# 1, 0,
# 1, 1, 1, 0,
# 1, 0,
# 1, 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 0,
# 1, 1, 1, 0,
# 1, 0,
# 1, 0
#------------------------------------------------------------------------------
# A071030 - rule 54, rows 2n+1
# 0,
# 1, 0, 1,
# 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
# 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
# 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
# 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
# 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
#------------------------------------------------------------------------------
# A071039 rule 190, rows 2n+1
# 1,
# 0, 1, 0,
# 1, 1, 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 1, 1,
# 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
# 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
# 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1
#------------------------------------------------------------------------------
# A071036 rule 150
# ** ** *** ** **
# * * * * *
# *** *** ***
# * * *
# ** * **
# * * *
# ***
# *
# 1,
# 0, 1, 1,
# 0, 1, 1, 0, 0,
# 0, 1, 1, 1, 1, 0, 1,
# 0, 1, 1, 0, 0, 0, 1, 1, 1,
# 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1,
# 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
# 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1,
# 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1,
# 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1
#------------------------------------------------------------------------------
# A071022 rule 70,198
# A071023 rule 78
# A071024 rule 92
# A071025 rule 124
# A071026 rule 188
# A071027 rule 230
# A071028 rule 50 ok
# A071029 rule 22
# A071030 rule 54 -- cf A118109 bits and A118108 bignum
# A071031 rule 62
# A071032 rule 86
# A071033 rule 94
# A071034 rule 118
# A071035 rule 126 sierpinski
# A071036 rule 150
# A071037 rule 158
# A071038 rule 182
# A071039 rule 190
# A071040 rule 214
# A071041 rule 246
#
# A071042 num 0s in A070886 rule 90 sierpinski ok
# A071043 num 0s in A071029 rule 22 ok
# A071044 num 1s in A071029 rule 22 ok
# A071045 num 0s in A071030 rule 54 ok
# A071046 num 0s in A071031 rule 62 ok
# A071047
# A071048
# A071049
# A071050
# A071051 num 1s in A071035 rule 126 sierpinski
# A071052
# A071053
# A071054
# A071055
#
exit 0;
Math-PlanePath-113/xt/oeis/TriangleSpiral-oeis.t 0000644 0001750 0001750 00000011557 12136177277 017361 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min', 'max';
use Math::PlanePath::TriangleSpiral;
use Math::PlanePath::TriangleSpiralSkewed;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $path = Math::PlanePath::TriangleSpiral->new;
#------------------------------------------------------------------------------
# A023531 -- N of turn position, OFFSET=0
MyOEIS::compare_values
(anum => 'A023531',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangleSpiral->new;
my @got;
my $n = $path->n_start;
my $prev_dxdy = join(',',$path->n_to_dxdy($n));
for ($n++; @got < $count; $n++) {
my $dxdy = join(',',$path->n_to_dxdy($n));
push @got, ($dxdy eq $prev_dxdy ? 0 : 1);
$prev_dxdy = $dxdy;
}
return \@got;
});
#------------------------------------------------------------------------------
# A081272 -- N on Y axis
MyOEIS::compare_values
(anum => 'A081272',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiral->new;
for (my $y = 0; @got < $count; $y -= 2) {
push @got, $path->xy_to_n (0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A081275 -- N on slope=3 ENE
MyOEIS::compare_values
(anum => 'A081275',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiral->new (n_start => 0);
my $x = 2;
my $y = 0;
while (@got < $count) {
push @got, $path->xy_to_n ($x,$y);
$x += 3;
$y += 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A081589 -- N on slope=3 ENE
MyOEIS::compare_values
(anum => 'A081589',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiral->new;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, $path->xy_to_n ($x,$y);
$x += 3;
$y += 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A038764 -- N on slope=2 WSW
MyOEIS::compare_values
(anum => 'A038764',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiral->new;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, $path->xy_to_n ($x,$y);
$x += -3;
$y += -1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A063177 -- a(n) is sum of existing numbers in row of a(n-1)
MyOEIS::compare_values
(anum => 'A063177',
func => sub {
my ($count) = @_;
my @got;
require Math::BigInt;
my %plotted;
$plotted{0,0} = Math::BigInt->new(1);
my $xmin = 0;
my $ymin = 0;
my $xmax = 0;
my $ymax = 0;
push @got, 1;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
my ($prev_x, $prev_y) = $path->n_to_xy ($n-1);
my ($x, $y) = $path->n_to_xy ($n);
### at: "$x,$y prev $prev_x,$prev_y"
my $total = 0;
if ($x > $prev_x) {
### forward diagonal ...
foreach my $y ($ymin .. $ymax) {
my $delta = $y - $prev_y;
my $x = $prev_x + $delta;
$total += $plotted{$x,$y} || 0;
}
} elsif ($y > $prev_y) {
### row: "$xmin .. $xmax at y=$prev_y"
foreach my $x ($xmin .. $xmax) {
$total += $plotted{$x,$prev_y} || 0;
}
} else {
### opp diagonal ...
foreach my $y ($ymin .. $ymax) {
my $delta = $y - $prev_y;
my $x = $prev_x - $delta;
$total += $plotted{$x,$y} || 0;
}
}
### total: "$total"
$plotted{$x,$y} = $total;
$xmin = min($xmin,$x);
$xmax = max($xmax,$x);
$ymin = min($ymin,$y);
$ymax = max($ymax,$y);
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/AlternatePaper-oeis.t 0000644 0001750 0001750 00000017452 12203071301 017320 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::AlternatePaper;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $paper = Math::PlanePath::AlternatePaper->new;
#------------------------------------------------------------------------------
# A106665 -- turn 1=left, 0=right
# OFFSET=0 cf first turn at N=1 here
MyOEIS::compare_values
(anum => 'A106665',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'AlternatePaper',
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A090678 "non-squashing partitions" A088567 mod 2
# and A121241 which is 1,-1
# almost but not quite arms=2 turn_type=Left
# A121241 1,-1
# A110036 2,0,-2
# A110037 1,0,-1
# MyOEIS::compare_values
# (anum => 'A090678',
# func => sub {
# my ($count) = @_;
# require Math::NumSeq::PlanePathTurn;
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'AlternatePaper,arms=2',
# turn_type => 'Left');
# my @got = (1,1,1,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1);
# while (@got < $count) {
# my ($i,$value) = $seq->next;
# push @got, $value;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A209615 Completely multiplicative with a(p^e) = 1 if p == 1 (mod 4),
# a(p^e) = (-1)^e otherwise.
MyOEIS::compare_values
(anum => 'A209615',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $paper,
turn_type => 'LSR');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A020985 - Golay/Rudin/Shapiro is dX and dY alternately
# also is dSum in Math::NumSeq::PlanePathDelta
MyOEIS::compare_values
(anum => q{A020985},
func => sub {
my ($count) = @_;
my @got;
for (my $n = $paper->n_start; @got < $count; ) {
{
my ($dx, $dy) = $paper->n_to_dxdy ($n++);
push @got, $dx;
}
last unless @got < $count;
{
my ($dx, $dy) = $paper->n_to_dxdy ($n++);
push @got, $dy;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A020991 - position of last occurance of n, last time of X+Y=n
MyOEIS::compare_values
(anum => 'A020991',
func => sub {
my ($count) = @_;
my @got;
my @occur;
my $target = 1;
for (my $n = $paper->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $paper->n_to_xy ($n);
my $d = $x + $y;
$occur[$d]++;
if ($occur[$d] == $d) {
push @got, $n-1;
$target++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A093573+1 - triangle of positions where cumulative=k
# cumulative A020986 starts n=0 for GRS(0)=0 (A020985)
# 0,
# 1, 3,
# 2, 4, 6,
# 5, 7, 13, 15,
# 8, 12, 14, 16, 26,
# 9, 11, 17, 19, 25, 27
#
# cf diagonals
# 0
# 1
# 2, 4
# 3,7, 5
# 8, 6,14, 16
# 9,13, 15,27, 17
MyOEIS::compare_values
(anum => 'A093573',
func => sub {
my ($count) = @_;
my @got;
OUTER: for (my $sum = 1; ; $sum++) {
my @n_list;
foreach my $y (0 .. $sum) {
my $x = $sum - $y;
push @n_list, $paper->xy_to_n_list($x,$y);;
}
@n_list = sort {$a<=>$b} @n_list;
foreach my $n (@n_list) {
last OUTER if @got >= $count;
push @got, $n-1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A020986 - GRS cumulative
# X+Y, starting from N=1 (doesn't have X+Y=0 for N=0)
MyOEIS::compare_values
(anum => 'A020986',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $paper->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $paper->n_to_xy ($n);
push @got, $x+$y;
}
return \@got;
});
# is X coord undoubled, starting from N=2 (doesn't have X=0 for N=0)
MyOEIS::compare_values
(anum => q{A020986},
func => sub {
my ($count) = @_;
my @got;
for (my $n = 2; @got < $count; $n += 2) {
my ($x, $y) = $paper->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A022155 - positions of -1, is S,W steps
MyOEIS::compare_values
(anum => 'A022155',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $paper->n_start; @got < $count; $n++) {
my ($dx,$dy) = $paper->n_to_dxdy($n);
if ($dx < 0 || $dy < 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A203463 - positions of 1, is N,E steps
MyOEIS::compare_values
(anum => 'A203463',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $paper->n_start; @got < $count; $n++) {
my ($dx,$dy) = $paper->n_to_dxdy($n);
if ($dx > 0 || $dy > 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A020990 - Golay/Rudin/Shapiro * (-1)^k cumulative, is Y coord undoubled,
# except N=0
MyOEIS::compare_values
(anum => 'A020990',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 2; @got < $count; $n += 2) {
my ($x, $y) = $paper->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A020990},
func => sub {
my ($count) = @_;
my @got;
for (my $n = $paper->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $paper->n_to_xy ($n);
push @got, $x-$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A212591 - position of first occurance of n, first time getting to X+Y=n
# seq 0, 1, 2, 5, 8, 9, 10, 21, 32, 33, 34, 37, 40, 41, 42, 85
# N 0 1 2 3 6, 9, 10, 11, 22, ...
MyOEIS::compare_values
(anum => 'A212591',
max_count => 1000, # because simple linear search
func => sub {
my ($count) = @_;
my @got;
my $target = 1;
for (my $n = $paper->n_start + 1; @got < $count; $n++) {
my ($x, $y) = $paper->n_to_xy ($n);
my $d = $x + $y;
if ($d == $target) {
push @got, $n-1;
$target++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/KochCurve-oeis.t 0000644 0001750 0001750 00000024111 12253775046 016316 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 8;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::KochCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A002450 number of right turns N=1 to N < 4^k
#
# 2
# / \ /
# 0---1 3---4
# A020988 number of left turns N=1 to N < 4^k = (2/3)*(4^n-1).
# duplicate A084180
MyOEIS::compare_values
(anum => 'A020988',
max_value => 100_000,
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Left');
my @got;
my $total = 0;
my $target = 1;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($i == $target) {
push @got, $total;
$target *= 4;
}
$total += $value;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A002450',
max_value => 100_000,
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Right');
my @got;
my $total = 0;
my $target = 1;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($i == $target) {
push @got, $total;
$target *= 4;
}
$total += $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A177702 - abs(dX) from N=1 onwards, repeating 1,1,2
MyOEIS::compare_values
(anum => 'A177702',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => 'KochCurve',
delta_type => 'AbsdX');
$seq->seek_to_i(1);
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A217586
# Not quite turn sequence ...
# differs 0<->1 at n=2^k
#
# a(1) = 1
# if a(n) = 0 then a(2*n) = 1 and a(2*n+1) = 0 # opposite low bit
# if a(n) = 1 then a(2*n) = 0 and a(2*n+1) = 0 # both 0
#
# a(2n+1)=0 # odd always left
# a(2n) = 1-a(n) # even 0 or 1 as odd or even
# a(4n) = 1-a(2n) = 1-(1-a(n)) = a(n)
# a(4n+2) = 1-a(2n+1) = 1-0 = 1 # 4n+2 always right
# except a(0+2) = 1-a(1) = 1-1 = 0
# A Right N differ
# 1 0 1 *
# 0 1 10 *
# 0 0 11
# 1 0 100 *
# 0 0 101
# 1 1 110
# 0 0 111
# 0 1 1000 *
# 0 0 1001
# 1 1 1010
# 0 0 1011
# 0 0 1100
# 0 0 1101
# 1 1 1110
# 0 0 1111
# 1 0 10000 *
# 0 0
# 1 1
# 0 0
# 0 0
# 0 0
# 1 1
# 0 0
# 1 1
MyOEIS::compare_values
(anum => q{A217586},
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Right');
my @got;
while (@got < $count) {
# $seq->next;
my ($i,$value) = $seq->next;
if (is_pow2($i)) { $value ^= 1; }
push @got, $value;
# push @got, A217586_func($i)
}
return \@got;
});
sub A217586_func {
my ($n) = @_;
if ($n < 1) {
die "A217586_func() must have n>=1";
}
{
while (($n & 3) == 0) {
$n >>= 2;
}
if ($n == 1) {
return 1;
}
if (($n & 3) == 2) {
if ($n == 2) { return 0; }
else { return 1; }
}
if ($n & 1) {
return 0;
}
}
# {
# if ($n == 1) {
# return 1;
# }
# if (A217586_func($n >> 1)) {
# if ($n & 1) {
# return 0;
# } else {
# return 0;
# }
# } else {
# if ($n & 1) {
# return 0;
# } else {
# return 1;
# }
# }
# }
#
# {
# if ($n == 1) {
# return 1;
# }
# my $bit = $n & 1;
# if (A217586_func($n >> 1)) {
# return 0;
# } else {
# return $bit ^ 1;
# }
# }
}
sub is_pow2 {
my ($n) = @_;
while ($n > 1) {
if ($n & 1) {
return 0;
}
$n >>= 1;
}
return ($n == 1);
}
#------------------------------------------------------------------------------
# A035263 is turn left=1,right=0 at OFFSET=1
# morphism 1 -> 10, 0 -> 11
MyOEIS::compare_values
(anum => 'A035263',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
# also left=0,right=1 at even N
MyOEIS::compare_values
(anum => 'A035263',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
if (($i & 1) == 0) {
push @got, $value;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A073059 a(4k+3)= 1 ..11 = 1
# a(4k+2) = a(4k+4) = 0 ..00 ..10 = 0
# a(16k+13) = 1 1101
# a(4n+1) = a(n) ..01 = base4 above
# a(n) = 1-A035263(n-1) is Koch 1=left,0=right by morphism OFFSET=1
# so A073059 is next turn 0=left,1=right
# ???
#
# MyOEIS::compare_values
# (anum => q{A073059},
# func => sub {
# my ($count) = @_;
# require Math::NumSeq::PlanePathTurn;
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
# turn_type => 'Left');
# my @got = (0);
# while (@got < $count) {
# $seq->next;
# my ($i,$value) = $seq->next;
# push @got, $value;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A096268 - morphism turn 1=right,0=left
# but OFFSET=0 is turn at N=1
MyOEIS::compare_values
(anum => 'A096268',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A029883 - Thue-Morse first diffs
MyOEIS::compare_values
(anum => 'A029883',
fixup => sub {
my ($bvalues) = @_;
@$bvalues = map {abs} @$bvalues;
},
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A089045 - +/- increment
MyOEIS::compare_values
(anum => 'A089045',
fixup => sub {
my ($bvalues) = @_;
@$bvalues = map {abs} @$bvalues;
},
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003159 - N end in even number of 0 bits, is positions of left turn
MyOEIS::compare_values
(anum => 'A003159',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value == 1) { # left
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A036554 - N end in odd number of 0 bits, position of right turns
MyOEIS::compare_values
(anum => 'A036554',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'KochCurve',
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value == 1) { # right
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/ZOrderCurve-oeis.t 0000644 0001750 0001750 00000014633 12136177276 016650 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 10;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::ZOrderCurve;
use Math::PlanePath::Diagonals;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A163328 -- radix=3 diagonals same axis
MyOEIS::compare_values
(anum => 'A163328',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $zorder->xy_to_n ($x, $y);
}
return \@got;
});
# A163329 -- radix=3 diagonals same axis, inverse
MyOEIS::compare_values
(anum => 'A163329',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $zorder->n_start; @got < $count; $n++) {
my ($x, $y) = $zorder->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A163330 -- radix=3 diagonals opposite axis
MyOEIS::compare_values
(anum => 'A163330',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $zorder->xy_to_n ($x, $y);
}
return \@got;
});
# A163331 -- radix=3 diagonals same axis, inverse
MyOEIS::compare_values
(anum => 'A163331',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new (radix => 3);
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down',
n_start => 0);
for (my $n = $zorder->n_start; @got < $count; $n++) {
my ($x, $y) = $zorder->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A054238 -- permutation, diagonals same axis
MyOEIS::compare_values
(anum => 'A054238',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy ($n);
push @got, $zorder->xy_to_n ($x, $y);
}
return \@got;
});
# A054239 -- diagonals same axis, inverse
MyOEIS::compare_values
(anum => 'A054239',
func => sub {
my ($count) = @_;
my @got;
my $zorder = Math::PlanePath::ZOrderCurve->new;
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
for (my $n = $zorder->n_start; @got < $count; $n++) {
my ($x, $y) = $zorder->n_to_xy ($n);
push @got, $diagonal->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A057300 -- N at transpose Y,X, radix=2
MyOEIS::compare_values
(anum => 'A057300',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ZOrderCurve->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163327 -- N at transpose Y,X, radix=3
MyOEIS::compare_values
(anum => 'A163327',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ZOrderCurve->new (radix => 3);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A126006 -- N at transpose Y,X, radix=4
MyOEIS::compare_values
(anum => 'A126006',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ZOrderCurve->new (radix => 4);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A217558 -- N at transpose Y,X, radix=16
MyOEIS::compare_values
(anum => 'A217558',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::ZOrderCurve->new (radix => 16);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x, $y) = ($y, $x);
my $n = $path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DiamondSpiral-oeis.t 0000644 0001750 0001750 00000013273 12136177302 017151 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
# use Smart::Comments '###';
use Math::PlanePath::DiamondSpiral;
my $path = Math::PlanePath::DiamondSpiral->new;
#------------------------------------------------------------------------------
# A184636 -- N on Y axis, from Y=2 onwards, if this really is 2*n^2
MyOEIS::compare_values
(anum => 'A184636',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::DiamondSpiral->new (n_start => 0);
my @got = (3);
for (my $y = 2; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A188551 -- N positions of turns Nstart=-1
MyOEIS::compare_values
(anum => 'A188551',
max_value => 100_000,
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'DiamondSpiral,n_start=-1',
turn_type => 'LSR');
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value != 0 && $i >= 1) {
push @got, $i;
}
}
return \@got;
});
# also prime
MyOEIS::compare_values
(anum => 'A188552',
max_value => 100_000,
func => sub {
my ($count) = @_;
my @got;
require Math::NumSeq::PlanePathTurn;
require Math::Prime::XS;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'DiamondSpiral,n_start=-1',
turn_type => 'LSR');
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value != 0
&& $i >= 1
&& Math::Prime::XS::is_prime($i)) {
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A217296 -- permutation DiamondSpiral -> SquareSpiral rotate +90
# 1 2 3 4 5 6 7 8
# 1, 4, 6, 8, 2, 3, 15, 5,
MyOEIS::compare_values
(anum => 'A217296',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::SquareSpiral;
my $square = Math::PlanePath::SquareSpiral->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
($x,$y) = (-$y,$x); # rotate +90
push @got, $square->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217015 -- permutation SquareSpiral rotate -90 -> DiamondSpiral
# 1 2 3 4 5 6
# 1, 5, 6, 2, 8, 3, 10, 4,
MyOEIS::compare_values
(anum => 'A217015',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::SquareSpiral;
my $square = Math::PlanePath::SquareSpiral->new;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy ($n);
($x,$y) = ($y,-$x); # rotate -90
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A215468 -- N sum 8 neighbours
MyOEIS::compare_values
(anum => 'A215468',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
+ $path->xy_to_n($x+1,$y+1)
+ $path->xy_to_n($x-1,$y-1)
+ $path->xy_to_n($x-1,$y+1)
+ $path->xy_to_n($x+1,$y-1));
}
return \@got;
});
#------------------------------------------------------------------------------
# A215471 -- primes with >=5 prime neighbours in 8 surround
MyOEIS::compare_values
(anum => 'A215471',
func => sub {
my ($count) = @_;
require Math::Prime::XS;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
my $num = ((!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y-1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x-1,$y+1)))
+ (!! Math::Prime::XS::is_prime ($path->xy_to_n($x+1,$y-1)))
);
if ($num >= 5) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/Staircase-oeis.t 0000644 0001750 0001750 00000002716 12164406220 016334 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 7;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Staircase;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A128918 -- N on X axis except initial 1,1
MyOEIS::compare_values
(anum => 'A128918',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Staircase->new (n_start => 2);
my @got = (1,1);
for (my $x = 0; @got < $count; $x++) {
my $n = $path->xy_to_n ($x, 0);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/GcdRationals-oeis.t 0000644 0001750 0001750 00000013007 12136177301 016767 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 6;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::GcdRationals;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A050873 = ceil(X/Y)
MyOEIS::compare_values
(anum => 'A050873',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new
(pairs_order => 'rows_reverse');
my @got;
my $n_start = $path->n_start;
for (my $n = $n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, div_ceil($x,$y);
}
return \@got;
});
sub div_ceil {
my ($n,$d) = @_;
return int (($n+$d-1) / $d);
}
#------------------------------------------------------------------------------
# A050873 = int(X/Y) + A023532
# so int(X/Y) = A050873 - A023532
{
my ($b2) = MyOEIS::read_values('A023532');
MyOEIS::compare_values
(anum => 'A050873',
max_count => scalar(@$b2),
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new;
my @got;
my $n_start = $path->n_start;
for (my $n = $n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, int($x/$y) + $b2->[$n-$n_start];
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A178340 Bernoulli denominator = int(X/Y) + 1
# Not quite since A178340 reduced rational. First different at n=49.
#
# MyOEIS::compare_values
# (anum => q{A178340},
# func => sub {
# my ($count) = @_;
# my $path = Math::PlanePath::GcdRationals->new;
# my @got = (1);
# for (my $n = $path->n_start; @got < $count; $n++) {
# my ($x,$y) = $path->n_to_xy($n);
# push @got, int($x/$y) + 1;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A033638 - diagonals_down X=1 column, quarter squares + 1, squares+pronic + 1
MyOEIS::compare_values
(anum => 'A033638',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new
(pairs_order => 'diagonals_down');
my @got = (1);
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002061 - X axis pairs_order=diagonals_up, central polygonals
MyOEIS::compare_values
(anum => 'A002061',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new
(pairs_order => 'diagonals_up');
my @got = (1);
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A000124 - Y axis pairs_order=rows (the default), triangular+1
MyOEIS::compare_values
(anum => 'A000124',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new;
my @got;
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A000290 - X axis pairs_order=diagonals_down, perfect squares
MyOEIS::compare_values
(anum => 'A000290',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new (pairs_order =>
'diagonals_down');
my @got = (0);
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002620 - Y axis pairs_order=diagonals_up, squares and pronic
MyOEIS::compare_values
(anum => 'A002620',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new
(pairs_order => 'diagonals_up');
my @got = (0,0);
for (my $y = 1; @got < $count; $y++) {
push @got, $path->xy_to_n(1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A002522 - Y=X+1 above diagonal pairs_order=diagonals_up, squares+1
MyOEIS::compare_values
(anum => 'A002522',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GcdRationals->new (pairs_order =>
'diagonals_up');
my @got = (1);
for (my $i = 1; @got < $count; $i++) {
push @got, $path->xy_to_n($i,$i+1);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/MPeaks-oeis.t 0000644 0001750 0001750 00000004220 12240244664 015575 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::MPeaks;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A056109 -- N on X negative axis
MyOEIS::compare_values
(anum => 'A056109',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::MPeaks->new;
for (my $x = -1; @got < $count; $x--) {
push @got, $path->xy_to_n ($x,0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A045944 -- N on X axis
MyOEIS::compare_values
(anum => 'A045944',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::MPeaks->new;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n ($x,0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A056106 -- N on Y axis
MyOEIS::compare_values
(anum => 'A056106',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::MPeaks->new;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n (0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PythagoreanTree-oeis.t 0000644 0001750 0001750 00000036573 12246036024 017531 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 2;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::BigInt try => 'GMP';
use Math::PlanePath::PythagoreanTree;
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A000244 = 3^n is N of A repeatedly in middle of row
MyOEIS::compare_values
(anum => 'A000244',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new;
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
push @got, ($path->tree_depth_to_n_end($depth)
+ $path->tree_depth_to_n($depth) + 1) / 2;
}
return \@got;
});
#------------------------------------------------------------------------------
# A052940 matrix T repeatedly coordinate P, binary 101111111111 = 3*2^n-1
MyOEIS::compare_values
(anum => 'A052940',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'PQ');
for (my $depth = Math::BigInt->new(1); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
# A055010 same
MyOEIS::compare_values
(anum => 'A055010',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'PQ');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
# A083329 same
MyOEIS::compare_values
(anum => 'A083329',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'PQ');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
# A153893 same
MyOEIS::compare_values
(anum => 'A153893',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'PQ');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
# A093357 matrix T repeatedly coordinate B, binary 10111..111000..000
MyOEIS::compare_values
(anum => 'A093357',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $y;
}
return \@got;
});
# A134057 matrix T repeatedly coordinate A, binomial(2^n-1,2)
# binary 111..11101000..0001
MyOEIS::compare_values
(anum => 'A134057',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0,0);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A106624 matrix K3 repeatedly P,Q pairs 2^k-1,2^k
MyOEIS::compare_values
(anum => 'A106624',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1,0);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'PQ');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054881 matrix K2 repeatedly "B" coordinate
MyOEIS::compare_values
(anum => 'A054881',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1,0);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $y;
}
return \@got;
});
# A015249 matrix K2 repeatedly "A" coordinate
MyOEIS::compare_values
(anum => 'A015249',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
# A084152 same
MyOEIS::compare_values
(anum => 'A084152',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0,0,1);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
# A084175 same
MyOEIS::compare_values
(anum => 'A084175',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0,1);
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A085601 = matrix K1 repeatedly "C" coordinate, binary 10010001
MyOEIS::compare_values
(anum => 'A085601',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AC');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y;
}
return \@got;
});
# A028403 = matrix K1 repeatedly "B" coordinate, binary 10010000
MyOEIS::compare_values
(anum => 'A028403',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y;
}
return \@got;
});
# A007582 = matrix K1 repeatedly "B/4" coordinate, binary 1001000
MyOEIS::compare_values
(anum => 'A007582',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y/4;
}
return \@got;
});
#------------------------------------------------------------------------------
# A084159 matrix A repeatedly "A" coordinate, Pell oblongs
MyOEIS::compare_values
(anum => 'A084159',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
# A046727 matrix A repeatedly "A" coordinate
MyOEIS::compare_values
(anum => 'A046727',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
# A046729 matrix A repeatedly "B" coordinate
MyOEIS::compare_values
(anum => 'A046729',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $y;
}
return \@got;
});
# A001653 matrix A repeatedly "C" coordinate
MyOEIS::compare_values
(anum => 'A001653',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AC');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $y;
}
return \@got;
});
# A001652 matrix A repeatedly "S" coordinate
MyOEIS::compare_values
(anum => 'A001652',
# max_count => 50,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'SM');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
# A046090 matrix A repeatedly "M" coordinate
MyOEIS::compare_values
(anum => 'A046090',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'SM');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $y;
}
return \@got;
});
# A000129 matrix A repeatedly "P" coordinate
MyOEIS::compare_values
(anum => 'A000129',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0,1);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy(3 ** $depth);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A099776 = matrix U repeatedly "C" coordinate
MyOEIS::compare_values
(anum => 'A099776',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got;
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AC');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y;
}
return \@got;
});
# A001844 centred squares same
MyOEIS::compare_values
(anum => 'A001844',
# max_count => 100,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (1);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AC');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y;
}
return \@got;
});
# A046092 matrix U repeatedly "B" coordinate = 4*triangular
MyOEIS::compare_values
(anum => 'A046092',
# max_count => 500,
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'AB');
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n($depth));
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A000466 matrix D repeatedly "A" coordinate = 4n^2-1
MyOEIS::compare_values
(anum => 'A000466',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (-1);
my $path = Math::PlanePath::PythagoreanTree->new;
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
my ($x,$y) = $path->n_to_xy($path->tree_depth_to_n_end($depth));
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A058529 - all prime factors == +/-1 mod 8
# is differences mid-small legs
MyOEIS::compare_values
(anum => 'A058529',
max_count => 35,
func => sub {
my ($count) = @_;
require Math::BigInt;
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'SM');
my %seen;
for (my $n = $path->n_start; $n < 100000; $n++) {
my ($s,$m) = $path->n_to_xy($n);
my $diff = $m - $s;
$seen{$diff} = 1;
}
my @got = sort {$a<=>$b} keys %seen;
$#got = $count-1;
return \@got;
});
#------------------------------------------------------------------------------
# A003462 = (3^n-1)/2 is tree_depth_to_n_end()
MyOEIS::compare_values
(anum => 'A003462',
func => sub {
my ($count) = @_;
require Math::BigInt;
my @got = (0);
my $path = Math::PlanePath::PythagoreanTree->new;
for (my $depth = Math::BigInt->new(0); @got < $count; $depth++) {
push @got, $path->tree_depth_to_n_end($depth);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/HypotOctant-oeis.t 0000644 0001750 0001750 00000006242 12136177301 016674 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min', 'max';
use Math::PlanePath::HypotOctant;
# uncomment this to run the ### lines
#use Smart::Comments '###';
# #------------------------------------------------------------------------------
# # A001844
#
# {
# my $anum = 'A001844';
# my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
#
# my $diff;
# if ($bvalues) {
# my @got;
# my $path = Math::PlanePath::HypotOctant->new;
# my $i = 0;
# for (my $i = 0; @got < $count; $i++) {
# push @got, $i*$i + ($i+1)*($i+1);
# }
#
# return \@got;
# if ($diff) {
# MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
# MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
# }
# }
# skip (! $bvalues,
# $diff,
# undef,
# "$anum");
# }
#------------------------------------------------------------------------------
# A057653
MyOEIS::compare_values
(anum => 'A057653',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::HypotOctant->new (points => 'odd');
my $prev = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my $rsquared = $path->n_to_rsquared($n);
if ($rsquared != $prev) {
$prev = $rsquared;
push @got, $rsquared;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A024507
MyOEIS::compare_values
(anum => 'A024507',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::HypotOctant->new;
my $i = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($y != 0 && $x != $y) {
push @got, $path->n_to_rsquared($n);
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A024509
MyOEIS::compare_values
(anum => 'A024509',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::HypotOctant->new;
my $i = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($y != 0) {
push @got, $path->n_to_rsquared($n);
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PyramidSides-oeis.t 0000644 0001750 0001750 00000002754 12136177277 017035 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 6;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PyramidSides;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A004201 -- N for which X>=0
MyOEIS::compare_values
(anum => 'A004201',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PyramidSides->new;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($x >= 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/WythoffArray-oeis.t 0000644 0001750 0001750 00000067037 12237271735 017066 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A141104 Lower Even Swappage of Upper Wythoff Sequence.
# A141105 Upper Even Swappage of Upper Wythoff Sequence.
# A141106 Lower Odd Swappage of Upper Wythoff Sequence.
# A141107 Upper Odd Swappage of Upper Wythoff Sequence.
use 5.004;
use strict;
use Carp;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::WythoffArray;
use Math::PlanePath::CoprimeColumns;
*_coprime = \&Math::PlanePath::CoprimeColumns::_coprime;
# uncomment this to run the ### lines
# use Smart::Comments '###';
sub BIGINT {
require Math::NumSeq::PlanePathN;
return Math::NumSeq::PlanePathN::_bigint();
}
# P+A=B P=B-A
sub pair_left_justify {
my ($a,$b) = @_;
my $count = 0;
while ($a <= $b) {
($a,$b) = ($b-$a,$a);
if ($count > 10) {
die "oops cannot left justify $a,$b";
}
}
return ($a,$b);
}
# path_find_row_with_pair() returns the row Y which contains the Fibonacci
# sequence which includes $a,$b somewhere, so W(X,Y)==$a and W(X+1,Y)==$b.
#
# If $a,$b are before the start of a row then the pair are stepped forward
# as necessary. So they specify a Fibonacci-type recurrent sequence which
# is sought.
#
sub path_find_row_with_pair {
my ($path, $a, $b) = @_;
### path_find_row_with_pair(): "$a, $b"
if (($a == 0 && $b == 0) || $b < 0) {
croak "path_find_row_with_pair $a,$b";
}
for (my $count = 0; $count < 50; ($a,$b) = ($b,$a+$b)) {
### at: "a=$a b=$b"
my ($x,$y) = $path->n_to_xy($a) or next;
if ($path->xy_to_n($x+1,$y) == $b) {
### found: " $a $b at X=$x, Y=$y"
return $y;
}
}
die "oops, pair $a,$b not found";
}
#------------------------------------------------------------------------------
# A186007 -- row(i+j) - row(i)
# R(4,1) row 4+1=5 sub row 1
# row=5 | 12 20 32 52 84 136 220 356 576 932 1508
# row=1 | 1 2 3 5 8 13 21 34 55 89 144
# 11 18 29
# tail of row2
# R(4,3) row 4+3=7 sub row 4
# row=7 | 17 28 45 73 118 191 309 500 809 1309 2118
# row=4 | 9 15 24 39 63 102 165 267 432 699 1131
# 8 13
# tail of row=1 fibs
# row=7 | 17 28 45 73 118 191 309 500 809 1309 2118
# row=3 | 6 10 16 26 42 68 110 178 288 466 754
# 11 18
# tail of row=2 lucas
# B-values
# 1, pos=0
# 1,1, pos=1 to 2
# 1,1, 1, pos=3 to 5
# 2,1, 3,1, pos=6 to 9
# 1,3, 1,1,1, pos=10 to 14
# 3,1, 1,1,1,1, pos=15 to 20
# 2,4, 3,3,2,1,1, pos=21 to 27
# 1,2, 8,1,3,1,1,1,
# 4,1, 1,3,1,2,1,3,1,
# 3,6, 4,2,4,1,3,1,1,1,
# 2,3,11,1,2,3,1,2,1,1,1,
# 5
# 1, pos=0
# 1,1, pos=1 to 2
# 1,1, 1, pos=3 to 5
# 2,1, 3,1, pos=6 to 9
# 1,3, 1,1,1, pos=10 to 14
# 3,1, 2,1,1,1, pos=15 to 20 <-
# 2,4, 1,3,2,1,1, pos=21 to 27 <-
# 1,2, 3,1,3,1,1,1,
# 4,1, 8,3,1,2,1,3,1,
# 3,6, 1,2,4,1,3,1,1,1,
# 2,3, 4,1,2,3,1,2,1,1,1,
# 5
# row 9 of W: 22,36,58,94,...
# row 3 of W: 6,10,16,26,...
#
# (row 9)-(row 3): 16,26,42,68 tail of row 3
# code 1....3....1....2....1....3....8....1....4....
# data 1....3....1.... 1....3....8....1....4....11
{
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
my $diag = Math::PlanePath::Diagonals->new (x_start=>1, y_start=>1,
direction => 'up',
n_start => 1);
sub my_A186007 {
my ($n) = @_;
if ($n < 1) { die; }
my ($i,$j) = $diag->n_to_xy($n); # by anti-diagonals
($i,$j) = ($i+$j, $j);
my $ia = $path->xy_to_n(1,$i) or die;
my $ib = $path->xy_to_n(2,$i) or die;
my $ja = $path->xy_to_n(1,$j) or die;
my $jb = $path->xy_to_n(2,$j) or die;
my $da = $ia-$ja;
my $db = $ib-$jb;
my $d = path_find_row_with_pair($path, $da,$db);
# print "n=$n i=$i iab=$ia,$ib j=$j jab=$ja,$jb diff=$da,$db at d=$d\n";
return $d;
}
# foreach my $y (1 .. 5) {
# print " ";
# foreach my $x (1 .. 10) {
# my $n = $diag->xy_to_n($x,$y);
# printf "%d....", my_A186007($n);
# }
# print "\n\n";
# }
#
# print "R(2,6) = ",$diag->xy_to_n(6,2),"\n";
}
MyOEIS::compare_values
(anum => 'A186007',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 1; @got < $count; $n++) {
push @got, my_A186007($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A185735 -- row(i)+row(j) of left-justified array
# 1 0 1 1 2 3
# 2 1 3 4 7 11
# 2 0 2 2 4 6
# 3 0 3 3 6 9
# 4 0 4 4 8 12
# 3 1 4 5 9 14
# row1+row2= 1,0+2,1 = 3,1 = row6
# row1+row3= 1,0+2,0 = 4,0 = row4
MyOEIS::compare_values
(anum => 'A185735',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
# Y>=1, 0<=Xnew (x_start=>1, y_start=>1);
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($i,$j) = $diag->n_to_xy($d); # by anti-diagonals
# if ($i > $j) { ($i,$j) = ($j,$i); }
my $ia = $path->xy_to_n(1,$i) or die;
my $ib = $path->xy_to_n(2,$i) or die;
my $ja = $path->xy_to_n(1,$j) or die;
my $jb = $path->xy_to_n(2,$j) or die;
($ia,$ib) = pair_left_justify($ia,$ib);
($ja,$jb) = pair_left_justify($ja,$jb);
push @got, path_find_row_with_pair($path, $ia+$ja, $ib+$jb);
}
return \@got;
});
#------------------------------------------------------------------------------
# A165357 - Left-justified Wythoff Array by diagonals
{
my $path = Math::PlanePath::WythoffArray->new;
sub left_justified_row_start {
my ($y) = @_;
return pair_left_justify($path->xy_to_n(0,$y),
$path->xy_to_n(1,$y));
}
sub left_justified_xy_to_n {
my ($x,$y) = @_;
my ($a,$b) = left_justified_row_start($y);
foreach (1 .. $x) {
($a,$b) = ($b,$a+$b);
}
return $a;
}
# foreach my $y (0 .. 5) {
# foreach my $x (0 .. 10) {
# printf "%3d ", left_justified_xy_to_n($x,$y);
# }
# print "\n";
# }
}
MyOEIS::compare_values
(anum => 'A165357',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, left_justified_xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A185737 -- accumulation array, by antidiagonals
# accumulation being total sum N in rectangle 0,0 to X,Y
MyOEIS::compare_values
(anum => 'A185737',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
require Math::PlanePath::Diagonals;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, path_rect_to_accumulation($path, 0,0, $x,$y)
}
return \@got;
});
sub path_rect_to_accumulation {
my ($path, $x1,$y1, $x2,$y2) = @_;
# $x1 = round_nearest ($x1);
# $y1 = round_nearest ($y1);
# $x2 = round_nearest ($x2);
# $y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
my $accumulation = 0;
foreach my $x ($x1 .. $x2) {
foreach my $y ($y1 .. $y2) {
$accumulation += $path->xy_to_n($x,$y);
}
}
return $accumulation;
}
#------------------------------------------------------------------------------
# A173028 -- row number which is x * row(y), by diagonals
# Return pair ($a,$b) which is in the $k'th coprime row of WythoffArray $path
# First pair at $k==1.
sub coprime_pair {
my ($path, $k) = @_;
my $x = $path->x_minimum;
for (my $y = $path->y_minimum; ; $y++) {
my $a = $path->xy_to_n($x, $y);
my $b = $path->xy_to_n($x+1,$y);
if (_coprime($a,$b)) {
$k--;
if ($k <= 0) {
return ($a,$b);
}
}
}
}
# Return the row number Y of WythoffArray $path which contains $multiple
# times the $k'th coprime row.
sub path_y_of_multiple {
my ($path, $multiple, $k) = @_;
### path_y_of_multiple: "$multiple,$k"
if ($multiple < 1) {
croak "path_y_of_multiple multiple=$multiple";
}
($a,$b) = coprime_pair($path,$k);
return path_find_row_with_pair($path, $a*$multiple, $b*$multiple);
}
# {
# my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
# foreach my $y (1 .. 5) {
# foreach my $x (1 .. 10) {
# printf "%3d ", path_y_of_multiple($path,$x,$y)//-1;
# }
# print "\n";
# }
# }
MyOEIS::compare_values
(anum => 'A173028',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
require Math::PlanePath::Diagonals;
my $diag = Math::PlanePath::Diagonals->new (x_start => $path->x_minimum,
y_start => $path->y_minimum,
direction => 'up');
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, path_y_of_multiple($path,$x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A139764 -- lowest Zeckendorf term fibonacci value,
# is N on X axis for the column containing n
MyOEIS::compare_values
(anum => 'A139764',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n($x,0); # down to axis
# Across to Y axis, not in OEIS
# push @got, $path->xy_to_n(0,$y); # across to axis
}
return \@got;
});
#------------------------------------------------------------------------------
# A114579 -- N at transpose Y,X
MyOEIS::compare_values
(anum => 'A114579',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy (BIGINT()->new($n));
my $t = $path->xy_to_n ($y, $x);
push @got, $t;
}
return \@got;
});
#------------------------------------------------------------------------------
# A220249 -- which row is n * Lucas numbers
MyOEIS::compare_values
(anum => 'A220249',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
my @got;
for (my $k = 1; @got < $count; $k++) {
# Lucas numbers starting 1, 3
push @got, path_find_row_with_pair($path, $k, $k*3);
}
return \@got;
});
#------------------------------------------------------------------------------
# A173027 -- which row is n * Fibonacci numbers
MyOEIS::compare_values
(anum => 'A173027',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffArray->new (x_start=>1, y_start=>1);
my @got;
for (my $k = 1; @got < $count; $k++) {
# Fibonacci numbers starting 1, 1
push @got, path_find_row_with_pair($path, $k, $k);
}
return \@got;
});
#------------------------------------------------------------------------------
# A035614 -- X coord, starting 0
# but is OFFSET=0 so start N=0
MyOEIS::compare_values
(anum => 'A035614',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A188436 -- [3r]-[nr]-[3r-nr], where r=(1+sqrt(5))/2 and []=floor.
# positions of right turns
# Y axis turn right: 0 1 00 101 00 1 00 101
# Fibonacci word: 0 1 00 101 00 1 00 101
#
# N on Y axis
# 101010
# 101001
# 100101
# 100001
# 10101
# 10001
# 1001
# 101
# 1
# A188436: 00000 001000000010000100000001000000010000100000001000010000000100000
# path: 001000000010000100000001000000010000100000001000010000000100000
MyOEIS::compare_values
(anum => 'A188436',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'WythoffArray',
turn_type => 'Right');
my @got = (0,0,0,0,0);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
use constant PHI => (1 + sqrt(5)) / 2;
use POSIX 'floor';
sub A188436_func {
my ($n) = @_;
floor(3*PHI) - floor($n*PHI)-floor(3*PHI-$n*PHI);
}
{
require Math::NumSeq::Fibbinary;
my $seq = Math::NumSeq::Fibbinary->new;
my $bad = 0;
foreach (1 .. 50000) {
my ($i,$seq_value) = $seq->next;
$seq_value = ($seq_value % 8 == 5 ? 1 : 0);
# if ($seq_value) { print "$i," }
my $func_value = A188436_func($i+4);
if ($func_value != $seq_value) {
print "$i fibbinary seq=$seq_value func=$func_value\n";
last if $bad++ > 20;
}
}
ok (0, $bad);
}
{
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'WythoffArray',
turn_type => 'Right');
my $bad = 0;
foreach (1 .. 50000) {
my ($i,$seq_value) = $seq->next;
my $func_value = A188436_func($i+4);
if ($func_value != $seq_value) {
print "$i turn seq=$seq_value func=$func_value\n";
last if $bad++ > 20;
}
}
ok (0, $bad);
}
# [3r]-[(n+4)r]-[3r-(n+4)r]
# = [3r]-[(n+4)r]-[3r-nr-4r]
# = [3r]-[nr+4r]-[-r-nr]
# some of Y axis 4,12,17,25,33,38,46
#------------------------------------------------------------------------------
# A003622 -- Y coordinate of right turns is "odd" Zeckendorf base
MyOEIS::compare_values
(anum => 'A003622',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $path = Math::PlanePath::WythoffArray->new;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value) {
my ($x,$y) = $path->n_to_xy($i);
$x == 0 or die "oops, right turn supposed to be at X=0";
push @got, $y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A134860 -- Wythoff AAB numbers
# N position of right turns, being Zeckendorf ending "...101"
MyOEIS::compare_values
(anum => 'A134860',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'WythoffArray',
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
if ($value) {
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# Y axis 0=left,1=right is Fibonacci word
{
require Math::NumSeq::PlanePathTurn;
require Math::NumSeq::FibonacciWord;
my $path = Math::PlanePath::WythoffArray->new;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my $fw = Math::NumSeq::FibonacciWord->new;
my $bad = 0;
foreach my $y (1 .. 1000) {
my $n = $path->xy_to_n(0, BIGINT()->new($y));
my $seq_value = $seq->ith($n);
my $fw_value = $fw->ith($y);
if ($fw_value != $seq_value) {
print "y=$y n=$n seq=$seq_value fw=$fw_value\n";
last if $bad++ > 20;
}
}
ok (0, $bad);
}
#------------------------------------------------------------------------------
# A080164 -- Wythoff difference array
# diff(x,y) = wythoff(2x+1,y) - wythoff(2x,y)
MyOEIS::compare_values
(anum => 'A080164',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffArray->new;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, $path->xy_to_n(2*$x+1,$y) - $path->xy_to_n(2*$x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A143299 number of Zeckendorf 1-bits in row Y
# cf A007895 which is the fibbinary bit count
MyOEIS::compare_values
(anum => 'A143299',
func => sub {
my ($count) = @_;
require Math::NumSeq::FibbinaryBitCount;
my $seq = Math::NumSeq::FibbinaryBitCount->new;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
for (my $y = 0; @got < $count; $y++) {
my $n = $path->xy_to_n(0,$y);
push @got, $seq->ith($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A137707 secondary Wythoff array ???
# A137707 Secondary Wythoff Array read by antidiagonals.
# A137708 Secondary Lower Wythoff Sequence.
# A137709 Secondary Upper Wythoff Sequence.
# MyOEIS::compare_values
# (anum => 'A137707',
# func => sub {
# my ($count) = @_;
# require Math::PlanePath::Diagonals;
# my $path = Math::PlanePath::WythoffArray->new;
# my $diag = Math::PlanePath::Diagonals->new;
# my @got;
# for (my $d = $diag->n_start; @got < $count; $d++) {
# my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
# if ($y % 2) {
# push @got, $path->xy_to_n($x,$y-1) + 1;
# } else {
# push @got, $path->xy_to_n($x,$y);
# }
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A083398 -- anti-diagonals needed to cover numbers 1 to n
# maybe n_range_to_rect() ...
# max(X+Y) for 1 to n
MyOEIS::compare_values
(anum => 'A083398',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
my @diag;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
$diag[$n] = $x+$y + 1; # +1 to count first diagonal as 1
push @got, max(@diag[1..$n]);
}
return \@got;
});
#------------------------------------------------------------------------------
# N in columns
foreach my $elem ([ 'A003622', 0 ], # N on Y axis, OFFSET=1
[ 'A035336', 1 ], # N in X=1 column OFFSET=1
[ 'A066097', 1 ], # N in X=1 column, duplicate OFFSET=0
# per list in A035513
[ 'A035337', 2 ], # OFFSET=0
[ 'A035338', 3 ], # OFFSET=0
[ 'A035339', 4 ], # OFFSET=0
[ 'A035340', 5 ], # OFFSET=0
) {
my ($anum, $x, %options) = @$elem;
MyOEIS::compare_values
(anum => $anum,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = @{$options{'extra_initial'}||[]};
for (my $y = BIGINT()->new(0); @got < $count; $y++) {
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A160997 Antidiagonal sums of the Wythoff array A035513
MyOEIS::compare_values
(anum => 'A160997',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my $d = 0;
my @got;
for (my $d = 0; @got < $count; $d++) {
my $total = 0;
foreach my $x (0 .. $d) {
$total += $path->xy_to_n($x,$d-$x);
}
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A005248 -- every second N on Y=1 row, every second Lucas number
MyOEIS::compare_values
(anum => q{A005248},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = (2,3); # initial skipped
for (my $x = BIGINT()->new(1); @got < $count; $x+=2) {
push @got, $path->xy_to_n ($x, 1);
}
return \@got;
});
#------------------------------------------------------------------------------
# N on rows
# per list in A035513
foreach my $elem ([ 'A000045', 0, extra_initial=>[0,1] ], # X axis Fibonaccis
[ 'A006355', 2, extra_initial=>[1,0,2,2,4] ],
[ 'A022086', 3, extra_initial=>[0,3,3,6] ],
[ 'A022087', 4, extra_initial=>[0,4,4,8] ],
[ 'A000285', 5, extra_initial=>[1,4,5,9] ],
[ 'A022095', 6, extra_initial=>[1,5,6,11] ],
# sum of Fibonacci and Lucas numbers
[ 'A013655', 7, extra_initial=>[3,2,5,7,12] ],
[ 'A022112', 8, extra_initial=>[2,6,8,14] ],
[ 'A022113', 9, extra_initial=>[2,7,9,16] ],
[ 'A022120', 10, extra_initial=>[3,7,10,17] ],
[ 'A022121', 11, extra_initial=>[3,8,11,19] ],
[ 'A022379', 12, extra_initial=>[3,9,12,21] ],
[ 'A022130', 13, extra_initial=>[4,9,13,22] ],
[ 'A022382', 14, extra_initial=>[4,10,14,24] ],
[ 'A022088', 15, extra_initial=>[0,5,5,10,15,25] ],
[ 'A022136', 16, extra_initial=>[5,11,16,27] ],
[ 'A022137', 17, extra_initial=>[5,12,17,29] ],
[ 'A022089', 18, extra_initial=>[0,6,6,12,18,30] ],
[ 'A022388', 19, extra_initial=>[6,13,19,32] ],
[ 'A022096', 20, extra_initial=>[1,6,7,13,20,33] ],
[ 'A022090', 21, extra_initial=>[0,7,7,14,21,35] ],
[ 'A022389', 22, extra_initial=>[7,15,22,37] ],
[ 'A022097', 23, extra_initial=>[1,7,8,15,23,38] ],
[ 'A022091', 24, extra_initial=>[0,8,8,16,24,40] ],
[ 'A022390', 25, extra_initial=>[8,17,25,42] ],
[ 'A022098', 26, extra_initial=>[1,8,9,17,26,43], ],
[ 'A022092', 27, extra_initial=>[0,9,9,18,27,45], ],
) {
my ($anum, $y, %options) = @$elem;
MyOEIS::compare_values
(anum => $anum,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = @{$options{'extra_initial'}||[]};
for (my $x = BIGINT()->new(0); @got < $count; $x++) {
push @got, $path->xy_to_n ($x, $y);
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A064274 -- inverse perm of by diagonals up from X axis
MyOEIS::compare_values
(anum => 'A064274',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'up');
my $wythoff = Math::PlanePath::WythoffArray->new;
my @got = (0); # extra 0
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $wythoff->n_to_xy ($n);
$x = BIGINT()->new($x);
$y = BIGINT()->new($y);
push @got, $diagonals->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A003849 -- Fibonacci word
MyOEIS::compare_values
(anum => 'A003849',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, ($x == 0 ? 1 : 0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A000201 -- N+1 for N not on Y axis, spectrum of phi
MyOEIS::compare_values
(anum => 'A000201',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = (1);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($x != 0) {
push @got, $n+1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A022342 -- N not on Y axis, even Zeckendorfs
MyOEIS::compare_values
(anum => 'A022342',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($x != 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A001950 -- N+1 of the N's on Y axis, spectrum
MyOEIS::compare_values
(anum => 'A001950',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffArray->new;
my @got;
for (my $y = 0; @got < $count; $y++) {
my $n = $path->xy_to_n(0,$y);
push @got, $n+1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A083412 -- by diagonals, down from Y axis
MyOEIS::compare_values
(anum => 'A083412',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'down');
my $wythoff = Math::PlanePath::WythoffArray->new;
my @got;
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
push @got, $wythoff->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A035513 -- by diagonals, up from X axis
MyOEIS::compare_values
(anum => 'A035513',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'up');
my $wythoff = Math::PlanePath::WythoffArray->new;
my @got;
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
$x = BIGINT()->new($x);
$y = BIGINT()->new($y);
push @got, $wythoff->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/TerdragonCurve-oeis.t 0000644 0001750 0001750 00000017730 12207311255 017353 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 12;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::TerdragonCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
my $path = Math::PlanePath::TerdragonCurve->new;
sub ternary_digit_above_low_zeros {
my ($n) = @_;
if ($n == 0) {
return 0;
}
while (($n % 3) == 0) {
$n = int($n/3);
}
return ($n % 3);
}
#------------------------------------------------------------------------------
# A136442 1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,0,0,
# OFFSET =0,1,2,3,...
# left 1,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0
# N=1,2,3,...
# Not quite
#
# MyOEIS::compare_values
# (anum => 'A136442',
# func => sub {
# my ($count) = @_;
# require Math::NumSeq::PlanePathTurn;
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
# turn_type => 'Left');
# my @got = (1);
# while (@got < $count) {
# my ($i, $value) = $seq->next;
# push @got, $value;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A060032 - turn 1=left, 2=right as bignums to 3^level
MyOEIS::compare_values
(anum => 'A060032',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'LSR');
my @got;
for (my $level = 0; @got < $count; $level++) {
require Math::BigInt;
my $big = Math::BigInt->new(0);
foreach my $n (1 .. 3**$level) {
my $value = $seq->ith($n);
if ($value == -1) { $value = 2; }
$big = 10*$big + $value;
}
push @got, $big;
}
return \@got;
});
#------------------------------------------------------------------------------
# A189673 - morphism turn 1=left, 0=right, extra initial 0
MyOEIS::compare_values
(anum => 'A189673',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Left');
my @got = (0);
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A189640 - morphism turn 0=left, 1=right, extra initial 0
MyOEIS::compare_values
(anum => 'A189640',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my @got = (0);
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A005823 - N positions with total turn == 0, no ternary 1s
MyOEIS::compare_values
(anum => 'A005823',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'LSR');
my $total_turn = 0;
my @got = (0);
while (@got < $count) {
my ($i, $value) = $seq->next;
$total_turn += $value;
if ($total_turn == 0) {
push @got, $i;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A062756 - ternary count 1s, is cumulative turn
MyOEIS::compare_values
(anum => 'A062756',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'LSR');
my @got;
my $cumulative = 0;
for (;;) {
push @got, $cumulative;
last if @got >= $count;
my ($i, $value) = $seq->next;
$cumulative += $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A080846 - turn 0=left, 1=right
MyOEIS::compare_values
(anum => 'A080846',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A038502 - taken mod 3 is 1=left, 2=right
MyOEIS::compare_values
(anum => 'A038502',
fixup => sub {
my ($bvalues) = @_;
@$bvalues = map { $_ % 3 } @$bvalues;
},
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i, $value) = $seq->next;
push @got, $value+1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A026225 - N positions of left turns
MyOEIS::compare_values
(anum => 'A026225',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Left');
my @got;
while (@got < $count) {
my ($i, $value) = $seq->next;
if ($value == 1) {
push @got, $i;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A026225',
func => sub {
my ($count) = @_;
my @got;
for (my $n = 1; @got < $count; $n++) {
if (ternary_digit_above_low_zeros($n) == 1) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A026179 - positions of right turns
MyOEIS::compare_values
(anum => 'A026179',
func => sub {
my ($count) = @_;
my @got = (1); # extra initial 1 ...
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
while (@got < $count) {
my ($i, $value) = $seq->next;
if ($value == 1) {
push @got, $i;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A026179',
func => sub {
my ($count) = @_;
my @got = (1);
for (my $n = 1; @got < $count; $n++) {
if (ternary_digit_above_low_zeros($n) == 2) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/HexSpiral-oeis.t 0000644 0001750 0001750 00000014101 12240242753 016310 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A182619 Number of vertices that are connected to two edges in a spiral without holes constructed with n hexagons.
# A182617 Number of toothpicks in a toothpick spiral around n cells on hexagonal net.
# A182618 Number of new grid points that are covered by the toothpicks added at n-th-stage to the toothpick spiral of A182617.
# A063178 Hexagonal spiral sequence: sequence is written as a hexagonal spiral around a `dummy' center, each entry is the sum of the row in the previous direction containing the previous entry.
# A063253 Values of A063178 on folding point positions of the spiral.
# A063254 Values of A062410 on folding point positions of the spiral.
# A063255 Values of A063177 on folding point positions of the spiral.
# A113519 Semiprimes in first spoke of a hexagonal spiral (A056105).
# A113524 Semiprimes in second spoke of a hexagonal spiral (A056106).
# A113525 Semiprimes in third spoke of a hexagonal spiral (A056107).
# A113527 Semiprimes in fourth spoke of a hexagonal spiral (A056108).
# A113528 Semiprimes in fifth spoke of a hexagonal spiral (A056109).
# A113530 Semiprimes in sixth spoke of a hexagonal spiral (A003215). Semiprime hex (or centered hexagonal) numbers.
# A113653 Isolated semiprimes in the hexagonal spiral.
use 5.004;
use strict;
use Test;
plan tests => 4;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min', 'max';
use Math::PlanePath::HexSpiral;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A135708 -- grid sticks of N hexagons
# /\ /\
# | | |
# \/ \/
MyOEIS::compare_values
(anum => 'A135708',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::HexSpiral->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
$boundary += 6 - triangular_num_preceding_neighbours($path,$n);
push @got, $boundary;
}
return \@got;
});
#------------------------------------------------------------------------------
# A135711 -- boundary length of N hexagons
# /\ /\
# | | |
# \/ \/
MyOEIS::compare_values
(anum => 'A135711',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::HexSpiral->new;
my @got;
my $boundary = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
$boundary += 6 - 2*triangular_num_preceding_neighbours($path,$n);
push @got, $boundary;
}
return \@got;
});
BEGIN {
my @surround6_dx = (2, 1,-1, -2, -1, 1);
my @surround6_dy = (0, 1, 1, 0, -1, -1);
sub triangular_num_preceding_neighbours {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy ($n);
my $count = 0;
foreach my $i (0 .. $#surround6_dx) {
my $n2 = $path->xy_to_n($x + $surround6_dx[$i],
$y + $surround6_dy[$i]);
$count += (defined $n2 && $n2 < $n);
}
return $count;
}
}
#------------------------------------------------------------------------------
# A063436 -- N on slope=3 WSW
MyOEIS::compare_values
(anum => 'A063436',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::HexSpiral->new (n_start => 0);
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, $path->xy_to_n ($x,$y);
$x -= 3;
$y -= 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A063178 -- a(n) is sum of existing numbers in row of a(n-1)
# 42
# \
# 2-----1 33
# / \ \
# 3 0-----1 23
# \ /
# 5-----8----10
#
# ^ ^ ^ ^ ^ ^ ^
MyOEIS::compare_values
(anum => 'A063178',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::HexSpiral->new;
my @got;
require Math::BigInt;
my %plotted;
$plotted{2,0} = Math::BigInt->new(1);
my $xmin = 0;
my $ymin = 0;
my $xmax = 2;
my $ymax = 0;
push @got, 1;
for (my $n = $path->n_start + 2; @got < $count; $n++) {
my ($prev_x, $prev_y) = $path->n_to_xy ($n-1);
my ($x, $y) = $path->n_to_xy ($n);
### at: "$x,$y prev $prev_x,$prev_y"
my $total = 0;
if (($y > $prev_y && $x < $prev_x)
|| ($y < $prev_y && $x > $prev_x)) {
### forward diagonal ...
foreach my $y ($ymin .. $ymax) {
my $delta = $y - $prev_y;
my $x = $prev_x + $delta;
$total += $plotted{$x,$y} || 0;
}
} elsif (($y == $prev_y && $x < $prev_x)
|| ($y == $prev_y && $x > $prev_x)) {
### opp diagonal ...
foreach my $y ($ymin .. $ymax) {
my $delta = $y - $prev_y;
my $x = $prev_x - $delta;
$total += $plotted{$x,$y} || 0;
}
} else {
### row: "$xmin .. $xmax at y=$prev_y"
foreach my $x ($xmin .. $xmax) {
$total += $plotted{$x,$prev_y} || 0;
}
}
### total: "$total"
$plotted{$x,$y} = $total;
$xmin = min($xmin,$x);
$xmax = max($xmax,$x);
$ymin = min($ymin,$y);
$ymax = max($ymax,$y);
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PentSpiralSkewed-oeis.t 0000644 0001750 0001750 00000004321 12240240721 017631 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 3;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PentSpiralSkewed;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A140066 - N on Y axis
MyOEIS::compare_values
(anum => 'A140066',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PentSpiralSkewed->new;
my @got;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A147875 - N on Y negative axis, n_start=0, second heptagonals
MyOEIS::compare_values
(anum => 'A147875',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PentSpiralSkewed->new (n_start => 0);
my @got;
for (my $y = 0; @got < $count; $y--) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A134238 - N on Y negative axis
MyOEIS::compare_values
(anum => 'A134238',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PentSpiralSkewed->new;
my @got;
for (my $y = 0; @got < $count; $y--) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/HIndexing-oeis.t 0000644 0001750 0001750 00000003012 12153014614 016261 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::HIndexing;
use Test;
plan tests => 11;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A097110 -- Y at N=2^k
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
MyOEIS::compare_values
(anum => 'A097110',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::HIndexing->new;
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/FilledRings-oeis.t 0000644 0001750 0001750 00000006432 12136177301 016623 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::BigInt;
use Math::PlanePath::FilledRings;
use Test;
plan tests => 5;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A036704 -- count |z|<=n+1/2
MyOEIS::compare_values
(anum => 'A036704',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::FilledRings->new (n_start => 0);
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,0);
}
return \@got;
});
#------------------------------------------------------------------------------
# A036708 -- half plane count n-1/2 < |z|<=n+1/2, b>=0
# first diffs of half plane count
# N(X)/2+X-1 - (N(X-1)/2+X-1-1)
# = (N(X)-N(X-1))/2 + X-1 - X + 2
# = (N(X)-N(X-1))/2 + 1
MyOEIS::compare_values
(anum => 'A036708',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::FilledRings->new;
for (my $x = 2; @got < $count; $x++) {
push @got, ($path->xy_to_n($x,0)-$path->xy_to_n($x-1,0))/2 + 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A036707 -- half plane count |z|<=n+1/2, b>=0
MyOEIS::compare_values
(anum => 'A036707',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::FilledRings->new;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,0)/2 + $x-1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A036706 -- 1/4 of first diffs of N along X axis,
MyOEIS::compare_values
(anum => 'A036706',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::FilledRings->new;
for (my $x = 1; @got < $count; $x++) {
push @got, int (($path->xy_to_n($x,0) - $path->xy_to_n($x-1,0)) / 4);
}
return \@got;
});
#------------------------------------------------------------------------------
# A036705 -- first diffs of N along X axis,
# count of z=a+bi satisfying n-1/2 < |z| <= n+1/2
MyOEIS::compare_values
(anum => 'A036705',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::FilledRings->new;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,0) - $path->xy_to_n($x-1,0);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PowerArray-oeis.t 0000644 0001750 0001750 00000033612 12167157313 016521 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 18;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PowerArray;
# uncomment this to run the ### lines
#use Smart::Comments '###';
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
#------------------------------------------------------------------------------
# A117303 -- permutation, N at transpose (2*x-1)*2^(y-1) <--> (2*y-1)*2^(x-1)
MyOEIS::compare_values
(anum => 'A117303',
func => sub {
my ($count) = @_;
require Math::PlanePath::PowerArray;
my $path = Math::PlanePath::PowerArray->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A151754 -- radix=10, Y at N=2^k starting k=1 N=2, floor(2^k*9/10)
MyOEIS::compare_values
(anum => 'A151754',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 10);
my @got;
for (my $n = $bigclass->new(2); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
$x == 0 or die;
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A000975 -- radix=3, Y at N=2^k, being Y=1010101..101 in binary
MyOEIS::compare_values
(anum => 'A000975',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 3);
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A050603 -- radix=2 abs(dX), but OFFSET=0
MyOEIS::compare_values
(anum => 'A050603',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $path->n_to_dxdy($n);
push @got, abs($dx);
}
return \@got;
});
#------------------------------------------------------------------------------
# A003159 -- radix=2, N which is in X even
MyOEIS::compare_values
(anum => 'A003159',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy($n);
if ($x % 2 == 0) {
push @got, $n;
}
}
return \@got;
});
# A036554 complement, N which is in X odd
MyOEIS::compare_values
(anum => 'A036554',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy($n);
if ($x % 2 == 1) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A007417 -- radix=3, N which is in X even
MyOEIS::compare_values
(anum => 'A007417',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 3);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy($n);
if ($x % 2 == 0) {
push @got, $n;
}
}
return \@got;
});
# A145204 complement, N which is in X odd, and extra initial 0
MyOEIS::compare_values
(anum => 'A145204',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PowerArray->new (radix => 3);
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy($n);
if ($x % 2 == 1) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A141396 -- radix=3, permutation, N by diagonals
MyOEIS::compare_values
(anum => 'A141396',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $power = Math::PlanePath::PowerArray->new (radix => 3);
my $diagonal = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $diagonal->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal->n_to_xy($n);
push @got, $power->xy_to_n ($x, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A191449 -- radix=3, permutation, N by diagonals up from X axis
MyOEIS::compare_values
(anum => 'A191449',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'up');
my $power = Math::PlanePath::PowerArray->new (radix => 3);
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
push @got, $power->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A135764 -- dispersion traversed by diagonals, down from Y axis
MyOEIS::compare_values
(anum => 'A135764',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'down');
my $power = Math::PlanePath::PowerArray->new;
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
push @got, $power->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A075300 -- dispersion traversed by diagonals, minus 1, so starts from 0
MyOEIS::compare_values
(anum => 'A075300',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'up');
my $power = Math::PlanePath::PowerArray->new;
my @got;
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
push @got, $power->xy_to_n($x,$y) - 1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A001651 -- radix=3, N on Y axis, not divisible by 3
MyOEIS::compare_values
(anum => 'A001651',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 3);
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A067251 -- radix=10, N on Y axis, no trailing 0 digits
MyOEIS::compare_values
(anum => 'A067251',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 10);
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A153733 remove trailing 1s
MyOEIS::compare_values
(anum => 'A153733',
func => sub {
my ($count) = @_;
my @got;
my $power = Math::PlanePath::PowerArray->new;
for (my $n = $power->n_start; @got < $count; $n++) {
my ($x, $y) = $power->n_to_xy ($n);
push @got, 2*$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A000265 -- 2*Y+1, odd part of n dividing out factors of 2
MyOEIS::compare_values
(anum => 'A000265',
func => sub {
my ($count) = @_;
my @got;
my $power = Math::PlanePath::PowerArray->new;
for (my $n = $power->n_start; @got < $count; $n++) {
my ($x, $y) = $power->n_to_xy ($n);
push @got, 2*$y+1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A094267 -- dX, but OFFSET=0
MyOEIS::compare_values
(anum => 'A094267',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $path->n_to_dxdy($n);
push @got, $dx;
}
return \@got;
});
#------------------------------------------------------------------------------
# A108715 -- dY
MyOEIS::compare_values
(anum => 'A108715',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx,$dy) = $path->n_to_dxdy($n);
push @got, $dy;
}
return \@got;
});
#------------------------------------------------------------------------------
# A118417 -- N on X=Y+1 diagonal
MyOEIS::compare_values
(anum => 'A118417',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
require Math::BigInt;
for (my $i = Math::BigInt->new(0); @got < $count; $i++) {
push @got, $path->xy_to_n($i+1,$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A005408 -- N on Y axis, odd numbers
MyOEIS::compare_values
(anum => 'A005408',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new;
for (my $y = 0; @got < $count; $y++) {
push @got, $path->xy_to_n(0,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A057716 -- N not on X axis, the non 2^X
MyOEIS::compare_values
(anum => 'A057716',
func => sub {
my ($count) = @_;
my @got = (0); # extra 0
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($y != 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A135765 -- odd numbers radix 3, down from Y axis
#
# 0 1 2 3 4 5 6
# 0 . . 3 4 . . 7 8 . . 11 12
# 2*y+($y%2)
#
# math-image --all --wx --path=PowerArray,radix=3 --output=numbers --size=15x20
#
# A135765 odd numbers by factors of 3
# product A000244 3^n, A007310 1or5 mod 6 is LCF>=5
# 1 5 7 11 13 17 19 23 25 29
# 3 15 21 33 39 51 57 69 75
# 9 25 63 99 117 153 171 207
# 27 135 189 297 351 459 513
# 81 405 567 891 1053 1377
# 243 1215 1701 2673 3159
# 729 3645 5103 8019
# 2187 10935 15309
# 6561 32805
#
MyOEIS::compare_values
(anum => 'A135765',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'down');
my $power = Math::PlanePath::PowerArray->new (radix => 3);
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
$y = 2*$y+($y%2); # stretch
push @got, $power->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A006519 -- 2^X coord
MyOEIS::compare_values
(anum => 'A006519',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, 2**$x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A025480 -- Y coord
MyOEIS::compare_values
(anum => 'A025480',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radix => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003602 -- Y+1 coord, k for which N=(2k-1)*2^m
MyOEIS::compare_values
(anum => 'A003602',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PowerArray->new (radixt => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $y+1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A054582 -- dispersion traversed by diagonals, up from X axis
MyOEIS::compare_values
(anum => 'A054582',
func => sub {
my ($count) = @_;
my @got;
require Math::PlanePath::Diagonals;
my $diagonals = Math::PlanePath::Diagonals->new (direction => 'up');
my $power = Math::PlanePath::PowerArray->new;
for (my $n = $diagonals->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonals->n_to_xy ($n);
push @got, $power->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/GrayCode-oeis.t 0000644 0001750 0001750 00000055320 12136177301 016116 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 33;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Base::Digits 'digit_split_lowtohigh';
use Math::PlanePath::GrayCode;
use Math::PlanePath::Diagonals;
use Math::PlanePath::Base::Digits
'digit_join_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A003188 -- Gray code radix=2 is ZOrder X,Y -> Gray TsF
# and Gray FsT X,Y -> ZOrder
MyOEIS::compare_values
(anum => 'A003188',
func => sub {
my ($count) = @_;
require Math::PlanePath::ZOrderCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'TsF');
my $zorder_path = Math::PlanePath::ZOrderCurve->new;
my @got;
for (my $n = $zorder_path->n_start; @got < $count; $n++) {
my ($x, $y) = $zorder_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A003188',
func => sub {
my ($count) = @_;
require Math::PlanePath::ZOrderCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'FsT');
my $zorder_path = Math::PlanePath::ZOrderCurve->new;
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my ($x, $y) = $gray_path->n_to_xy ($n);
my $n = $zorder_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A006068 -- ungray, inverse Gray TsT X,Y -> ZOrder N
# and ZOrder X,Y -> Gray FsF
MyOEIS::compare_values
(anum => 'A006068',
func => sub {
my ($count) = @_;
require Math::PlanePath::ZOrderCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'TsF');
my $zorder_path = Math::PlanePath::ZOrderCurve->new;
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my ($x, $y) = $gray_path->n_to_xy ($n);
my $n = $zorder_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
# A006068 -- ungray, ZOrder X,Y -> Gray FsT N
MyOEIS::compare_values
(anum => 'A006068',
func => sub {
my ($count) = @_;
require Math::PlanePath::ZOrderCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'FsT');
my $zorder_path = Math::PlanePath::ZOrderCurve->new;
my @got;
for (my $n = $zorder_path->n_start; @got < $count; $n++) {
my ($x, $y) = $zorder_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A064707 -- permutation radix=2 TsF -> FsT
# inverse square of A003188 Gray code
# A064706 -- permutation radix=2 FsT -> TsF
# square of A003188 Gray code ZOrder->TsF
# not same as A100281,A100282
MyOEIS::compare_values
(anum => q{A064707},
func => sub {
my ($count) = @_;
my $TsF_path = Math::PlanePath::GrayCode->new (apply_type => 'TsF');
my $FsT_path = Math::PlanePath::GrayCode->new (apply_type => 'FsT');
my @got;
for (my $n = $TsF_path->n_start; @got < $count; $n++) {
my ($x, $y) = $TsF_path->n_to_xy ($n);
my $n = $FsT_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A064706},
func => sub {
my ($count) = @_;
my $TsF_path = Math::PlanePath::GrayCode->new (apply_type => 'TsF');
my $FsT_path = Math::PlanePath::GrayCode->new (apply_type => 'FsT');
my @got;
for (my $n = $FsT_path->n_start; @got < $count; $n++) {
my ($x, $y) = $FsT_path->n_to_xy ($n);
my $n = $TsF_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
# {
# my $seq = Math::NumSeq::OEIS->new(anum=>'A099896');
# sub A100281_by_twice {
# my ($i) = @_;
# $i = $seq->ith($i);
# if (defined $i) { $i = $seq->ith($i); }
# return $i;
# }
# }
# sub A100281_by_func {
# my ($i) = @_;
# $i = ($i ^ ($i>>1) ^ ($i>>2));
# $i = ($i ^ ($i>>1) ^ ($i>>2));
# return $i;
# }
#------------------------------------------------------------------------------
# A099896 -- permutation Peano radix=2 -> Gray sF, from N=1 onwards
# n XOR [n/2] XOR [n/4]
# 1, 3, 2, 7, 6, 4, 5, 14, 15, 13, 12, 9, 8, 10, 11, 28, 29, 31, 30, 27,
# to_gray = n xor n/2
# PeanoCurve radix=2
#
# 54--55 49--48 43--42 44--45 64--65 71--70 93--92 90--91 493-492
# | | | | | | | | |
# 53--52 50--51 40--41 47--46 67--66 68--69 94--95 89--88 494-495
#
# 56--57 63--62 37--36 34--35 78--79 73--72 83--82 84--85 483-482
# | | | | | | | | |
# 59--58 60--61 38--39 33--32 77--76 74--75 80--81 87--86 480-481
#
# 13--12 10--11 16--17 23--22 123-122 124-125 102-103 97--96 470-471
# | | | | | | | | |
# 14--15 9-- 8 19--18 20--21 120-121 127-126 101-100 98--99 469-468
#
# 3-- 2 4-- 5 30--31 25--24 117-116 114-115 104-105 111-110 472-473
# | | | | | | | | |
# 0-- 1 7-- 6 29--28 26--27 118-119 113-112 107-106 108-109 475-474
# apply_type => "sF"
#
# 7 | 32--33 37--36 52--53 49--48
# | / \ / \
# 6 | 34--35 39--38 54--55 51--50
# |
# 5 | 42--43 47--46 62--63 59--58
# | \ / \ /
# 4 | 40--41 45--44 60--61 57--56
# |
# 3 | 8-- 9 13--12 28--29 25--24
# | / \ / \
# 2 | 10--11 15--14 30--31 27--26
# |
# 1 | 2-- 3 7-- 6 22--23 19--18
# | \ / \ /
# Y=0 | 0-- 1 5-- 4 20--21 17--16
# |
# +---------------------------------
# X=0 1 2 3 4 5 6 7
MyOEIS::compare_values
(anum => 'A099896',
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $peano_path = Math::PlanePath::PeanoCurve->new (radix => 2);
my @got;
for (my $n = 1; @got < $count; $n++) {
my ($x, $y) = $peano_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
# A100280 -- inverse
MyOEIS::compare_values
(anum => 'A100280',
func => sub {
my ($count) = @_;
require Math::PlanePath::PeanoCurve;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $peano_path = Math::PlanePath::PeanoCurve->new (radix => 2);
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my ($x, $y) = $gray_path->n_to_xy ($n);
my $n = $peano_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003159 -- (N+1)/2 of positions of Left turns
MyOEIS::compare_values
(anum => 'A003159',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::GrayCode->new;
for (my $n = 2; @got < $count; $n += 2) {
if (path_n_turn($path,$n) == 1) {
push @got, $n/2;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A036554 -- (N+1)/2 of positions of Left turns
MyOEIS::compare_values
(anum => 'A036554',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GrayCode->new;
my @got;
for (my $n = 2; @got < $count; $n += 2) {
if (path_n_turn($path,$n) == 0) {
push @got, $n/2;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A039963 -- Left turns
MyOEIS::compare_values
(anum => 'A039963',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GrayCode->new;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n++) {
push @got, path_n_turn($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A035263 -- Left turns undoubled, skip N even
MyOEIS::compare_values
(anum => 'A035263',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GrayCode->new;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n += 2) {
push @got, path_n_turn($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A065882 -- low base4 non-zero digit
MyOEIS::compare_values
(anum => 'A065882',
fixup => sub {
my ($bvalues) = @_;
foreach (@$bvalues) { $_ %= 2; }
},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GrayCode->new;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n += 2) {
push @got, path_n_turn($path,$n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A007913 -- Left turns from square free part of N, skip N even
MyOEIS::compare_values
(anum => q{A007913}, # not xreffed in GrayCode.pm
fixup => sub {
my ($bvalues) = @_;
foreach (@$bvalues) { $_ %= 2; }
},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::GrayCode->new;
my @got;
for (my $n = $path->n_start + 1; @got < $count; $n += 2) {
push @got, path_n_turn($path,$n);
}
return \@got;
});
# return 1 for left, 0 for right
sub path_n_turn {
my ($path, $n) = @_;
my $prev_dir = path_n_dir ($path, $n-1);
my $dir = path_n_dir ($path, $n);
my $turn = ($dir - $prev_dir) % 4;
if ($turn == 1) { return 1; }
if ($turn == 2) { return 0; }
die "Oops, unrecognised turn";
}
# return 0,1,2,3
sub path_n_dir {
my ($path, $n) = @_;
my ($dx,$dy) = $path->n_to_dxdy($n) or die "Oops, no point at ",$n;
return dxdy_to_dir ($dx, $dy);
}
# return 0,1,2,3, with Y reckoned increasing upwards
sub dxdy_to_dir {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # north
if ($dy < 0) { return 3; } # south
}
#------------------------------------------------------------------------------
# A163233 -- permutation diagonals sF
MyOEIS::compare_values
(anum => 'A163233',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $diagonal_path->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
# A163234 -- diagonals sF inverse
MyOEIS::compare_values
(anum => 'A163234',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'up',
n_start => 0);
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my ($x, $y) = $gray_path->n_to_xy ($n);
my $n = $diagonal_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163235 -- diagonals sF, opposite side start
MyOEIS::compare_values
(anum => 'A163235',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $diagonal_path->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
push @got, $n;
}
return \@got;
});
# A163236 -- diagonals sF inverse, opposite side start
MyOEIS::compare_values
(anum => 'A163236',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my ($x, $y) = $gray_path->n_to_xy ($n);
my $n = $diagonal_path->xy_to_n ($x, $y);
push @got, $n + $gray_path->n_start - $diagonal_path->n_start;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163237 -- diagonals sF, same side start, flip base-4 digits 2,3
sub flip_base4_23 {
my ($n) = @_;
my @digits = digit_split_lowtohigh($n,4);
foreach my $digit (@digits) {
if ($digit == 2) { $digit = 3; }
elsif ($digit == 3) { $digit = 2; }
}
return digit_join_lowtohigh(\@digits,4);
}
MyOEIS::compare_values
(anum => 'A163237',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $diagonal_path->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
$n = flip_base4_23($n);
push @got, $n;
}
return \@got;
});
# A163238 -- inverse
MyOEIS::compare_values
(anum => 'A163238',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my $n = flip_base4_23($n);
my ($x, $y) = $gray_path->n_to_xy ($n);
$n = $diagonal_path->xy_to_n ($x, $y);
push @got, $n + $gray_path->n_start - $diagonal_path->n_start;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163239 -- diagonals sF, opposite side start, flip base-4 digits 2,3
MyOEIS::compare_values
(anum => 'A163239',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $diagonal_path->n_start; @got < $count; $n++) {
my ($x, $y) = $diagonal_path->n_to_xy ($n);
my $n = $gray_path->xy_to_n ($x, $y);
$n = flip_base4_23($n);
push @got, $n;
}
return \@got;
});
# A163240 -- inverse
MyOEIS::compare_values
(anum => 'A163240',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my $diagonal_path = Math::PlanePath::Diagonals->new (direction => 'down');
my @got;
for (my $n = $gray_path->n_start; @got < $count; $n++) {
my $n = flip_base4_23($n);
my ($x, $y) = $gray_path->n_to_xy ($n);
$n = $diagonal_path->xy_to_n ($x, $y);
push @got, $n + $gray_path->n_start - $diagonal_path->n_start;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163242 -- sF diagonal sums
MyOEIS::compare_values
(anum => 'A163242',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my @got;
for (my $y = 0; @got < $count; $y++) {
my $sum = 0;
foreach my $i (0 .. $y) {
$sum += $gray_path->xy_to_n ($i, $y-$i);
}
push @got, $sum;
}
return \@got;
});
#------------------------------------------------------------------------------
# A163478 -- sF diagonal sums, divided by 3
MyOEIS::compare_values
(anum => 'A163478',
func => sub {
my ($count) = @_;
my $gray_path = Math::PlanePath::GrayCode->new (apply_type => 'sF');
my @got;
for (my $y = 0; @got < $count; $y++) {
my $sum = 0;
foreach my $i (0 .. $y) {
$sum += $gray_path->xy_to_n ($i, $y-$i);
}
push @got, $sum / 3;
}
return \@got;
});
#------------------------------------------------------------------------------
# A003188 - binary gray reflected
# modular and reflected same in binary
MyOEIS::compare_values
(anum => 'A003188',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A003188',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
# A014550 - binary gray reflected, in binary
MyOEIS::compare_values
(anum => 'A014550',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,10);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A014550',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,10);
}
return \@got;
});
# A006068 - binary gray reflected inverse
MyOEIS::compare_values
(anum => 'A006068',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A006068',
func => sub {
my ($count) = @_;
my $radix = 2;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
#------------------------------------------------------------------------------
# A105530 - ternary gray modular
MyOEIS::compare_values
(anum => 'A105530',
func => sub {
my ($count) = @_;
my $radix = 3;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
# A105529 - ternary gray modular inverse
MyOEIS::compare_values
(anum => 'A105529',
func => sub {
my ($count) = @_;
my $radix = 3;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
#------------------------------------------------------------------------------
# A128173 - ternary gray reflected
# odd radix to and from are the same
MyOEIS::compare_values
(anum => 'A128173',
func => sub {
my ($count) = @_;
my $radix = 3;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A128173',
func => sub {
my ($count) = @_;
my $radix = 3;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
#------------------------------------------------------------------------------
# A003100 - decimal gray reflected
MyOEIS::compare_values
(anum => 'A003100',
func => sub {
my ($count) = @_;
my $radix = 10;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
# A174025 - decimal gray reflected inverse
MyOEIS::compare_values
(anum => 'A174025',
func => sub {
my ($count) = @_;
my $radix = 10;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_reflected($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
#------------------------------------------------------------------------------
# A098488 - decimal gray modular
MyOEIS::compare_values
(anum => 'A098488',
func => sub {
my ($count) = @_;
my $radix = 10;
my @got;
for (my $n = 0; @got < $count; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_modular($digits,$radix);
push @got, digit_join_lowtohigh($digits,$radix);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/SierpinskiCurve-oeis.t 0000644 0001750 0001750 00000006055 12153015455 017547 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 14;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::SierpinskiCurve;
use Math::NumSeq::PlanePathDelta;
use Math::NumSeq::PlanePathTurn;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A081026 -- X at N=2^k
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
MyOEIS::compare_values
(anum => 'A081026',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiCurve->new;
my @got = (1);
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A081706 - N-1 positions of left turns
MyOEIS::compare_values
(anum => 'A081706',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiCurve',
turn_type => 'Left');
my @got;
for (my $n = $seq->i_start; @got < $count; $n++) {
my ($i,$value) = $seq->next;
if ($value) { # if a left turn
push @got, $i-1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A039963 - turn 1=right,0=left
# R,R L,L R,R
MyOEIS::compare_values
(anum => 'A039963',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiCurve',
turn_type => 'Right');
my @got;
for (my $n = $seq->i_start; @got < $count; $n++) {
push @got, $seq->ith($n);
}
return \@got;
});
#------------------------------------------------------------------------------
# A127254 - abs(dY) extra initial 1
MyOEIS::compare_values
(anum => 'A127254',
func => sub {
my ($count) = @_;
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => 'SierpinskiCurve',
delta_type => 'AbsdY');
my @got = (1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/Diagonals-oeis.t 0000644 0001750 0001750 00000020703 12153016342 016313 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 12;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Diagonals;
# uncomment this to run the ### lines
#use Smart::Comments '###';
# A079824
#------------------------------------------------------------------------------
# A057046 -- X at N=2^k
require Math::NumSeq::PlanePathN;
my $bigclass = Math::NumSeq::PlanePathN::_bigint();
{
my $path = Math::PlanePath::Diagonals->new (n_start => 1,
x_start => 1, y_start => 1);
MyOEIS::compare_values
(anum => 'A057046',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x;
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A057047',
func => sub {
my ($count) = @_;
my @got;
for (my $n = $bigclass->new(1); @got < $count; $n *= 2) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
}
#------------------------------------------------------------------------------
# A185787 -- total N in row up to Y=X diagonal
MyOEIS::compare_values
(anum => 'A185787',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got;
for (my $y = 0; @got < $count; $y++) {
push @got, path_rect_to_accumulation ($path, 0,$y, $y,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A100182 -- total N in column to X=Y leading diagonal
# tetragonal anti-prism numbers (7*n^3 - 3*n^2 + 2*n)/6
MyOEIS::compare_values
(anum => 'A100182',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got;
for (my $x = 0; @got < $count; $x++) {
push @got, path_rect_to_accumulation ($path, $x,0, $x,$x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A185788 -- total N in row to X=Y-1 before leading diagonal
MyOEIS::compare_values
(anum => 'A185788',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got = (0);
for (my $y = 1; @got < $count; $y++) {
push @got, path_rect_to_accumulation ($path, 0,$y, $y-1,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A101165 -- total N in column up to Y=X-1 before leading diagonal
MyOEIS::compare_values
(anum => 'A101165',
max_count => 1000,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got = (0);
for (my $x = 1; @got < $count; $x++) {
push @got, path_rect_to_accumulation ($path, $x,0, $x,$x-1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A185506 -- accumulation array, by antidiagonals
# accumulation being total sum N in rectangle 0,0 to X,Y
MyOEIS::compare_values
(anum => 'A185506',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got;
for (my $d = $path->n_start; @got < $count; $d++) {
my ($x,$y) = $path->n_to_xy($d); # by anti-diagonals
push @got, path_rect_to_accumulation($path, 0,0, $x,$y)
}
return \@got;
});
sub path_rect_to_accumulation {
my ($path, $x1,$y1, $x2,$y2) = @_;
# $x1 = round_nearest ($x1);
# $y1 = round_nearest ($y1);
# $x2 = round_nearest ($x2);
# $y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
my $accumulation = 0;
foreach my $x ($x1 .. $x2) {
foreach my $y ($y1 .. $y2) {
$accumulation += $path->xy_to_n($x,$y);
}
}
return $accumulation;
}
#------------------------------------------------------------------------------
# A103451 -- turn 1=left or right, 0=straight
# but has extra n=1 whereas path first turn at starts N=2
MyOEIS::compare_values
(anum => 'A103451',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'Diagonals',
turn_type => 'LSR');
my @got = (1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, abs($value);
}
return \@got;
});
#------------------------------------------------------------------------------
# A103452 -- turn 1=left,0=straight,-1=right
# but has extra n=1 whereas path first turn at starts N=2
MyOEIS::compare_values
(anum => 'A103452',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'Diagonals',
turn_type => 'LSR');
my @got = (1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A215200 -- Kronecker(n-k,k) by rows, n>=1 1<=k<=n
# for n=6 runs n-k=5,4,3,2,1,0 for n=1 runs n-k=0
# k=1,2,3,4,5,6 k=1
# x=n-k y=k is diagonal up from X axis
MyOEIS::compare_values
(anum => q{A215200},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new (direction => 'up',
x_start => 0,
y_start => 1);
require Math::NumSeq::PlanePathCoord;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, Math::NumSeq::PlanePathCoord::_kronecker_symbol($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A038722 -- permutation N at transpose Y,X, n_start=1
MyOEIS::compare_values
(anum => 'A038722',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A038722',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A061579 -- permutation N at transpose Y,X
MyOEIS::compare_values
(anum => 'A061579',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Diagonals->new (n_start => 0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A061579',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::Diagonals->new (n_start => 0,
direction => 'up');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, $path->xy_to_n ($y, $x);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/TriangleSpiralSkewed-oeis.t 0000644 0001750 0001750 00000023717 12136177277 020525 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# "type-2" skewed to the right
#
# 4
# / |
# 14 4 5 3 ... skew="right"
# 13 3 5 / | |
# 12 2 1 6 6 1--2 12
# 11 10 9 8 7 / |
# 7--8--9--10-11
# "type-3" diagonal first 29
# 16 15 14 13-12-11 28
# /
# 7 17 4--3--2 10 27 skew="up"
# 6 8 | / /
# 5 1 9 18 5 1 9 26
# 4 3 2 10 | /
# 15 14 13 12 11 19 6 8 25
# | /
# 20 7 24
# /
# 21 23
# |/
# 22
# TriangleSpiralSkewed
#
# 4
# |\
# 5 3 ...
# | \ \
# 6 1--2 12
# | \
# 7--8--9-10-11
#
use 5.004;
use strict;
use Test;
plan tests => 14;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use List::Util 'min', 'max';
use Math::PlanePath::TriangleSpiralSkewed;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A214230 -- sum of 8 neighbouring N, skew="left"
MyOEIS::compare_values
(anum => 'A214230',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangleSpiralSkewed->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, path_n_sum_surround8($path,$n);
}
return \@got;
});
# A214251 -- sum of 8 neighbouring N, "type 2" skew="right"
MyOEIS::compare_values
(anum => 'A214251',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'right');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, path_n_sum_surround8($path,$n);
}
return \@got;
});
# A214252 -- sum of 8 neighbouring N, "type 3" skew="up"
MyOEIS::compare_values
(anum => 'A214252',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'up');
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, path_n_sum_surround8($path,$n);
}
return \@got;
});
sub path_n_sum_surround8 {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy ($n);
return ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
+ $path->xy_to_n($x+1,$y+1)
+ $path->xy_to_n($x-1,$y-1)
+ $path->xy_to_n($x-1,$y+1)
+ $path->xy_to_n($x+1,$y-1));
}
#------------------------------------------------------------------------------
# A214231 -- sum of 4 neighbouring N
MyOEIS::compare_values
(anum => 'A214231',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::TriangleSpiralSkewed->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
push @got, path_n_sum_surround4($path,$n);
}
return \@got;
});
sub path_n_sum_surround4 {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy ($n);
return ($path->xy_to_n($x+1,$y)
+ $path->xy_to_n($x-1,$y)
+ $path->xy_to_n($x,$y+1)
+ $path->xy_to_n($x,$y-1)
);
}
#------------------------------------------------------------------------------
# A081272 -- N on slope=2 SSE
MyOEIS::compare_values
(anum => 'A081272',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiralSkewed->new;
my $x = 0;
my $y = 0;
while (@got < $count) {
push @got, $path->xy_to_n ($x,$y);
$x += 1;
$y -= 2;
}
return \@got;
});
#------------------------------------------------------------------------------
# A081275 -- N on X=Y+1 diagonal
MyOEIS::compare_values
(anum => 'A081275',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::TriangleSpiralSkewed->new (n_start => 0);
for (my $y = 0; @got < $count; $y++) {
my $x = $y + 1;
push @got, $path->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217010 -- permutation N values by SquareSpiral order
MyOEIS::compare_values
(anum => 'A217010',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new;
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy ($n);
push @got, $tsp->xy_to_n ($x,$y);
}
return \@got;
});
# A217291 -- inverse, TriangleSpiralSkewed X,Y order, SquareSpiral N
MyOEIS::compare_values
(anum => 'A217291',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new;
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $tsp->n_start; @got < $count; $n++) {
my ($x, $y) = $tsp->n_to_xy ($n);
push @got, $square->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217011 -- permutation N values by SquareSpiral order, type-2, skew="right"
# SquareSpiral North first then clockwise
# Triangle West first then clockwise
# rotate 90 degrees to compensate
MyOEIS::compare_values
(anum => 'A217011',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'right');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy ($n);
($x,$y) = (-$y,$x); # rotate +90
push @got, $tsp->xy_to_n ($x,$y);
}
return \@got;
});
# A217292 -- inverse, TriangleSpiralSkewed X,Y order, SquareSpiral N
MyOEIS::compare_values
(anum => 'A217292',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'right');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $tsp->n_start; @got < $count; $n++) {
my ($x, $y) = $tsp->n_to_xy ($n);
($x,$y) = ($y,-$x); # rotate -90
push @got, $square->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217012 -- permutation N values by SquareSpiral order, type-3, skew="up"
# SquareSpiral North first then clockwise
# Triangle South-East first then clockwise
# rotate 90 degrees to compensate
MyOEIS::compare_values
(anum => 'A217012',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'up');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy ($n);
($x,$y) = ($y,-$x); # rotate -90
push @got, $tsp->xy_to_n ($x,$y);
}
return \@got;
});
# A217293 -- inverse, TriangleSpiralSkewed X,Y order, SquareSpiral N
MyOEIS::compare_values
(anum => 'A217293',
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'up');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $tsp->n_start; @got < $count; $n++) {
my ($x, $y) = $tsp->n_to_xy ($n);
($x,$y) = (-$y,$x); # rotate +90
push @got, $square->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A217012 -- permutation N values by SquareSpiral order
# SquareSpiral North first then clockwise
# Triangle South-East first then clockwise
# rotate 180 degrees to compensate to skew="down"
MyOEIS::compare_values
(anum => q{A217012},
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'down');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $square->n_start; @got < $count; $n++) {
my ($x, $y) = $square->n_to_xy ($n);
($x,$y) = (-$x,-$y); # rotate 180
push @got, $tsp->xy_to_n ($x,$y);
}
return \@got;
});
# A217293 -- inverse, TriangleSpiralSkewed X,Y order, SquareSpiral N
MyOEIS::compare_values
(anum => q{A217293},
func => sub {
my ($count) = @_;
require Math::PlanePath::SquareSpiral;
my $tsp = Math::PlanePath::TriangleSpiralSkewed->new (skew => 'down');
my $square = Math::PlanePath::SquareSpiral->new;
my @got;
for (my $n = $tsp->n_start; @got < $count; $n++) {
my ($x, $y) = $tsp->n_to_xy ($n);
($x,$y) = (-$x,-$y); # rotate 180
push @got, $square->xy_to_n ($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/PyramidRows-oeis.t 0000644 0001750 0001750 00000016507 12154061007 016700 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
use List::Util 'sum';
plan tests => 5;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::PyramidRows;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A053615 -- distance to pronic is abs(X)
MyOEIS::compare_values
(anum => 'A053615',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PyramidRows->new (n_start => 0);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
push @got, abs($x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A103451 -- turn 1=left or right, 0=straight
# but has extra n=1 whereas path first turn at starts N=2
MyOEIS::compare_values
(anum => 'A103451',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'PyramidRows,step=1',
turn_type => 'LSR');
my @got = (1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, abs($value);
}
return \@got;
});
#------------------------------------------------------------------------------
# A103452 -- turn 1=left,0=straight,-1=right
# but has extra n=1 whereas path first turn at starts N=2
MyOEIS::compare_values
(anum => 'A103452',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'PyramidRows,step=1',
turn_type => 'LSR');
my @got = (1);
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
# A050873 -- step=1 GCD(X+1,Y+1) by rows
MyOEIS::compare_values
(anum => 'A050873',
func => sub {
my ($count) = @_;
require Math::PlanePath::GcdRationals;
my $path = Math::PlanePath::PyramidRows->new (step => 1);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, Math::PlanePath::GcdRationals::_gcd($x+1,$y+1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A051173 -- step=1 LCM(X+1,Y+1) by rows
MyOEIS::compare_values
(anum => 'A051173',
func => sub {
my ($count) = @_;
require Math::PlanePath::GcdRationals;
my $path = Math::PlanePath::PyramidRows->new (step => 1);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
push @got, ($x+1) * ($y+1)
/ Math::PlanePath::GcdRationals::_gcd($x+1,$y+1);
}
return \@got;
});
#------------------------------------------------------------------------------
# A215200 -- Kronecker(n-k,k) by rows, n>=1 1<=k<=n
MyOEIS::compare_values
(anum => q{A215200},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PyramidRows->new (step => 1);
require Math::NumSeq::PlanePathCoord;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy ($n);
next if $x == 0 || $y == 0;
my $n = $y;
my $k = $x;
push @got, Math::NumSeq::PlanePathCoord::_kronecker_symbol($n-$k,$k);
}
return \@got;
});
#------------------------------------------------------------------------------
# A004201 -- N for which X>=0, step=2
MyOEIS::compare_values
(anum => 'A004201',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PyramidRows->new (step => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
if ($x >= 0) {
push @got, $n;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A079824 -- diagonal sums
# cf A079825 with rows numbered alternately left and right
# a(21)=(n/6)*(7*n^2-6*n+5)
MyOEIS::compare_values
(anum => 'A079824',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::PyramidRows->new(step=>1);
for (my $y = 0; @got < $count; $y++) {
my @diag;
foreach my $i (0 .. $y) {
my $n = $path->xy_to_n($i,$y-$i);
next if ! defined $n;
push @diag, $n;
}
my $total = sum(@diag);
push @got, $total;
# if ($y <= 21) {
# MyTestHelpers::diag (join('+',@diag)," = $total");
# }
}
return \@got;
});
#------------------------------------------------------------------------------
# A000217 -- step=1 X=Y diagonal, the triangular numbers from 1
MyOEIS::compare_values
(anum => 'A000217',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::PyramidRows->new (step => 1);
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n($i,$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A000290 -- step=2 X=Y diagonal, the squares from 1
MyOEIS::compare_values
(anum => 'A000290',
func => sub {
my ($count) = @_;
my @got = (0);
my $path = Math::PlanePath::PyramidRows->new (step => 2);
for (my $i = 0; @got < $count; $i++) {
push @got, $path->xy_to_n($i,$i);
}
return \@got;
});
#------------------------------------------------------------------------------
# A167407 -- dDiffXY step=1, extra initial 0
MyOEIS::compare_values
(anum => 'A167407',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::PyramidRows->new (step => 1);
my @got = (0);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($dx, $dy) = $path->n_to_dxdy ($n);
push @got, $dx-$dy;
}
return \@got;
});
#------------------------------------------------------------------------------
# A010052 -- step=2 dY, 1 at squares
MyOEIS::compare_values
(anum => 'A010052',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::PyramidRows->new (step => 2);
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my ($next_x, $next_y) = $path->n_to_xy ($n+1);
push @got, $next_y - $y;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/FibonacciWordFractal-oeis.t 0000644 0001750 0001750 00000003147 12207313504 020423 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::FibonacciWordFractal;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A003849 - Fibonacci word 0/1, 0=straight,1=left or right
MyOEIS::compare_values
(anum => 'A003849',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'FibonacciWordFractal',
turn_type => 'LSR'); # turn_type=Straight
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value == 0 ? 1 : 0;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/DivisibleColumns-oeis.t 0000644 0001750 0001750 00000005133 12136177301 017671 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 3;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::DivisibleColumns;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A077597 - N on X=Y diagonal, being cumulative count divisors - 1
MyOEIS::compare_values
(anum => 'A077597',
func => sub {
my ($count) = @_;
my @got;
my $path = Math::PlanePath::DivisibleColumns->new;
for (my $x = 1; @got < $count; $x++) {
push @got, $path->xy_to_n($x,$x);
}
return \@got;
});
#------------------------------------------------------------------------------
# A027751 - Y coord, proper divisors, extra initial 1
MyOEIS::compare_values
(anum => 'A027751',
func => sub {
my ($count) = @_;
my @got = (1);
my $path = Math::PlanePath::DivisibleColumns->new
(divisor_type => 'proper');
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A006218 - cumulative count of divisors
{
my $anum = 'A006218';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my $good = 1;
my $count = 0;
if ($bvalues) {
my $path = Math::PlanePath::DivisibleColumns->new;
for (my $i = 0; $i < @$bvalues; $i++) {
my $x = $i+1;
my $want = $bvalues->[$i];
my $got = $path->xy_to_n($x,1);
if ($got != $want) {
MyTestHelpers::diag ("wrong totient sum xy_to_n($x,1)=$got want=$want at i=$i of $filename");
$good = 0;
}
$count++;
}
}
ok ($good, 1, "$anum count $count");
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/Hypot-oeis.t 0000644 0001750 0001750 00000014677 12136645623 015545 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Hypot;
# uncomment this to run the ### lines
# use Smart::Comments '###';
#------------------------------------------------------------------------------
# A199015 -- partial sums of A008441
MyOEIS::compare_values
(anum => 'A199015',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Hypot->new(points=>'square_centred');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 2;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + $y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/4;
$want_norm += 8;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A005883 -- count points with norm==4*n+1
# Theta series of square lattice with respect to deep hole.
#
# same as "odd" turned 45-degrees
#
# 3 . 2 . 2 . 3
#
# . . . . . . .
#
# 2 . 1 . 1 . 2
#
# . . . o . . .
#
# 2 . 1 . 1 . 2
#
# . . . . . . .
#
# 3 . 2 . 2 . 3
#
# 4, 8, 4, 8,8,0,12,8,0,8,8,8,4,8,0,8,16,0,8,0,4
MyOEIS::compare_values
(anum => 'A005883',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Hypot->new(points=>'square_centred');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 2;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + $y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 8;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
# A008441 = A005883/4
# how many ways to write n = x(x+1)/2 + y(y+1)/2 sum two triangulars
MyOEIS::compare_values
(anum => 'A008441',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Hypot->new(points=>'square_centred');
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 2;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
my $norm = $x*$x + $y*$y;
if ($norm > $want_norm) {
### push: $num
push @got, $num/4;
$want_norm += 8;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
# MyOEIS::compare_values
# (anum => 'A005883',
# func => sub {
# my ($count) = @_;
# my @got;
# my $path = Math::PlanePath::Hypot->new (points => 'square_centred');
# my $n = $path->n_start;
# my $i = 0;
# for (my $i = 0; @got < $count; $i++) {
# my $points = 0;
# for (;;) {
# my $h = $path->n_to_rsquared($n);
# if ($h > 4*$i+1) {
# last;
# }
# $points++;
# $n++;
# }
# ### $points
# push @got, $points;
# }
# return \@got;
# });
#------------------------------------------------------------------------------
# A004020 Theta series of square lattice with respect to edge.
# 2,4,2,4,4
#
# 2 . 2 .
#
# . . . . . .
#
# . 1 o 1 .
#
# . . . .
#
# . 2 . 2 .
#
# Y mod 2 == 0
# X mod 2 == 1
# X+2Y mod 4 == 1
sub xy_is_edge {
my ($x, $y) = @_;
return ($y%2 == 0 && $x%2 == 1);
}
MyOEIS::compare_values
(anum => q{A004020}, # with zeros
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::Hypot->new;
my @got;
my $n = $path->n_start;
my $num = 0;
my $want_norm = 1;
while (@got < $count) {
my ($x,$y) = $path->n_to_xy($n);
if (! xy_is_edge($x,$y)) {
$n++;
next;
}
my $norm = $path->n_to_rsquared($n);
if ($norm > $want_norm) {
### push: $num
push @got, $num;
$want_norm += 4;
$num = 0;
} else {
### point: "$n at $x,$y norm=$norm total num=$num"
$n++;
$num++;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A093837 - denominators N(r) / r^2
{
my $path = Math::PlanePath::Hypot->new;
sub Nr {
my ($r) = @_;
my $n = $path->xy_to_n($r,0);
for (;;) {
my $m = $n+1;
my ($x,$y) = $path->n_to_xy($m);
if ($x*$x+$y*$y > $r*$r) {
return $n;
}
$n = $m;
}
}
}
MyOEIS::compare_values
(anum => q{A093837},
func => sub {
my ($count) = @_;
require Math::BigRat;
my @got;
for (my $r = 1; @got < $count; $r++) {
my $Nr = Nr($r);
my $rsquared = $r*$r;
my $frac = Math::BigRat->new("$Nr/$rsquared");
push @got, $frac->denominator;
}
return \@got;
});
#------------------------------------------------------------------------------
# A093832 - N(r) / r^2 > pi
use Math::Trig 'pi';
MyOEIS::compare_values
(anum => q{A093832},
func => sub {
my ($count) = @_;
require Math::BigRat;
my @got;
for (my $r = 1; @got < $count; $r++) {
my $Nr = Nr($r);
my $rsquared = $r*$r;
if ($Nr / $rsquared > pi) {
push @got, $r;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/SierpinskiTriangle-oeis.t 0000644 0001750 0001750 00000057576 12144140340 020236 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 16;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::BigInt try => 'GMP';
use Math::NumSeq::BalancedBinary;
use Math::PlanePath::SierpinskiTriangle;
use Math::PlanePath::KochCurve;
*_digit_join_hightolow = \&Math::PlanePath::KochCurve::_digit_join_hightolow;
# uncomment this to run the ### lines
# use Smart::Comments '###';
# {
# my $path = Math::PlanePath::SierpinskiTriangle->new;
# print branch_reduced_breadth_bits($path,4);
# exit 0;
# }
#------------------------------------------------------------------------------
{
my $bal = Math::NumSeq::BalancedBinary->new;
# $aref is an arrayref of 1,0 bits.
sub dyck_bits_to_index {
my ($aref) = @_;
my $value = _digit_join_hightolow($aref, 2, Math::BigInt->new(0));
return $bal->value_to_i($value);
}
}
#------------------------------------------------------------------------------
# A130047 - left half Pascal mod 2
MyOEIS::compare_values
(anum => 'A130047',
fixup => sub {
my ($bvalues) = @_;
splice @$bvalues, 16,0, 1; # dodgy samples
},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $y = 0; @got < $count; $y++) {
for (my $x = -$y; $x <= 0 && @got < $count; $x += 2) {
push @got, $path->xy_is_visited($x,$y) ? 1 : 0;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# Branch-reduced breadth-wise
#
# Nodes with just 1 child are collapsed out.
# cf Homeomorphic same if dropping/adding single-child nodes
#
# A080318 decimal
# A080319 binary
# A080320 positions in A014486 list of balanced
#
# 10, branch reduced
# 111000,
# 11111110000000,
# 1111111-11000011-0000000,
# 11111111100001111111111000000000000000,
#
# . .
# *
# plain 10
#
# . . . .
#
# * *
# \ /
# *
# plain 111000
#
# . . . .
#
# * . . *
# \ / . . . .
# * * * *
# \ / \ /
# * *
# plain 1111001000 reduced 111000
#
# . . . . . . . .
# * * * *
# \ / \ / . . .... ..
# * . . * * * * *
# \ / \ / \ /
# * * * *
# \ / \ /
# * *
# plain reduced 11111110000000
#
# . . . .
# * *
# \ . . . . . . /
# * * * *
# \ / \ /
# * . . *
# \ /
# * *
# \ /
# *
#
# . . . . . . . .
# * * * *
# \ / \ /
# * *
# \ . . . . . . / . . . . . . . . 7 trailing
# * * * * * * * *
# \ / \ / \ / ....\ /
# * . . * * * * *
# \ / \ / \ /
# * * * *
# \ / \ /
# * *
# reduced 1111111110000110000000
#
# * * * *
# \ . . / \ . . /
# * * * *
# \ / \ /
# * *
# \ . . . . . . /
# * * * *
# \ / \ /
# * . . *
# \ /
# * *
# \ /
# *
#
# * * * * * * * *
# \ / \ / \ / \ /
# * * * *
# \ . . / \ . . /
# * * * *
# \ / \ / .. .. ............ 15 trailing
# * * * * * * * * * *
# \ . . . . . . / \ / \/ \/ \/
# * * * * * * * *
# \ / \ / \ / ....\ /
# * . . * * * * *
# \ / \ / \ /
# * * * *
# \ / \ /
# * *
# reduced 11111111100001111111111000000000000000
#
# 1111111110000111111111111000000000000110000000
# 11111111100001111111111110000000000001111111111000000000000000
# [9] [4] [12] [12] [10] [15]#
#
# 331698516757016399905370236824584576
# 11111111100001111111111110000000000001111111111110000111100001111111\
# 11111111111110000000000000000000000000000110000000
# 2 0 0 0 0 0 0 2 2 0 0 0 0 0 0 2
# 11 2 2 2 2 2 2 2 2
# 10 2 0 0 2 2 0 0 2
# 9 2 2 0 0 0 0 2 2
## 6 2 2 2 2
# 5 2 0 0 2
# 3 2 2
# 2 2
# 0
{
# double-up check
my ($one) = MyOEIS::read_values('A080268');
my ($two) = MyOEIS::read_values('A080318');
my $path = Math::PlanePath::SierpinskiTriangle->new;
require Math::BigInt;
for (my $i = 0; $i <= $#$one && $i+1 <= $#$two; $i++) {
my $o = $one->[$i];
my $t = $two->[$i+1];
my $ob = Math::BigInt->new("$o")->as_bin;
$ob =~ s/^0b//;
my $o2 = $ob;
$o2 =~ s/(.)/$1$1/g; # double
$o2 = "1".$o2."0";
my $tb = Math::BigInt->new("$t")->as_bin;
$tb =~ s/^0b//;
# print "o $o\nob $ob\no2 $o2\ntb $tb\n\n";
$tb eq $o2 or die "x";
}
}
# decimal, by path
MyOEIS::compare_values
(anum => 'A080318',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 0; @got < $count; $depth++) {
### $depth
my @bits = branch_reduced_breadth_bits($path, $depth);
### @bits
push @got, _digit_join_hightolow(\@bits, 2, Math::BigInt->new(0));
}
return \@got;
});
# binary, by path
MyOEIS::compare_values
(anum => 'A080319',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
# foreach my $depth (0 .. 11) {
# my @bits = branch_reduced_breadth_bits($path, $depth);
# print @bits,"\n";
# }
my @got;
for (my $depth = 0; @got < $count; $depth++) {
my @bits = branch_reduced_breadth_bits($path, $depth);
push @got, _digit_join_hightolow(\@bits, 10, Math::BigInt->new(0));
}
return \@got;
});
# position in list of all balanced binary (A014486)
MyOEIS::compare_values
(anum => 'A080320',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 0; @got < $count; $depth++) {
my @bits = branch_reduced_breadth_bits($path, $depth);
push @got, dyck_bits_to_index(\@bits);
}
return \@got;
});
# Return a list of 0,1 bits.
#
sub branch_reduced_breadth_bits {
my ($path, $limit) = @_;
my @pending_n = ($path->n_start);
my @ret;
foreach (0 .. $limit) {
### pending_n: join(',',map{$_//'undef'}@pending_n)
my @new_n;
foreach my $n (@pending_n) {
if (! defined $n) {
push @ret, 0;
next;
}
my ($x,$y) = $path->n_to_xy($n);
push @ret, 1;
$y += 1;
foreach my $dx (-1, 1) {
my $n_child = $path->xy_to_n($x+$dx,$y);
if (defined $n_child) {
$n_child = path_tree_n_branch_reduce($path,$n_child);
}
push @new_n, $n_child;
}
}
@pending_n = @new_n;
}
### final ...
### pending_n: join(',',map{$_//'undef'}@pending_n)
### ret: join('',@ret) . ' ' .('0' x $#pending_n)
return @ret, ((0) x $#pending_n);
}
# sub path_tree_n_branch_reduced_children {
# my ($path, $n) = @_;
# for (;;) {
# my @n_children = $path->tree_n_children($n);
# if (@n_children != 1) {
# return @n_children;
# }
# $n = $n_children[0];
# }
# }
# If $n has only 1 child then descend through it and any further
# 1-child nodes to return an N which has 2 or more children.
# If all the descendents of $n are 1-child then return undef.
sub path_tree_n_branch_reduce {
my ($path, $n) = @_;
my @n_children = $path->tree_n_children($n);
if (@n_children == 1) {
do {
$n = $n_children[0];
@n_children = $path->tree_n_children($n) or return undef;
} while (@n_children == 1);
}
return $n;
}
# Return $x,$y moved down to a "branch reduced" position, if necessary.
# A branch reduced tree has all nodes as either leaves or with 2 or more
# children. If $x,$y has only 1 child then follow down that child node and
# any 1-child nodes below, until reaching a 0 or 2 or more node. If $x,$y
# already has 0 or 2 or more then it's returned unchanged.
#
sub path_tree_xy_branch_reduced {
my ($path, $x,$y) = @_;
for (;;) {
my @xy_list = path_tree_xy_children($path, $x,$y);
if (@xy_list == 2) {
($x,$y) = @xy_list; # single child, descend
} else {
last; # multiple children or nothing, return this $x,$y
}
}
return ($x,$y);
}
# Return a list ($x1,$y1, $x2,$y2, ...) which are the children of $x,$y.
sub path_tree_xy_children {
my ($path, $x,$y) = @_;
return map {$path->n_to_xy($_)}
map {$path->tree_n_children($_)}
$path->xy_to_n_list($x,$y);
}
# Return the number of children of $x,$y, or undef if $x,$y is not visited.
sub path_tree_xy_num_children {
my ($path, $x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
if (! defined $n) { return undef; }
return $path->tree_n_num_children($path,$n);
}
# Return true if $x,$y is a leaf node, ie. has no children.
sub path_tree_xy_is_leaf {
my ($path, $x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
if (! defined $n) { return undef; }
return path_tree_n_is_leaf($path,$n);
}
# Return true if $n is a leaf node, ie. has no children.
sub path_tree_n_is_leaf {
my ($path, $n) = @_;
my $num_children = $path->tree_n_num_children($n);
if (! defined $num_children) { return undef; }
return $num_children == 0;
}
# Return a list of 0,1 bits.
#
sub DOUBLEUP_branch_reduced_breadth_bits {
my ($path, $limit) = @_;
my @pending_x = (0);
my @pending_y = (0);
my @ret = (1);
foreach (1 .. $limit) {
my @new_x;
my @new_y;
foreach my $i (0 .. $#pending_x) {
my $x = $pending_x[$i];
my $y = $pending_y[$i];
if ($path->xy_is_visited($x,$y)) {
push @ret, 1,1;
push @new_x, $x-1;
push @new_y, $y+1;
push @new_x, $x+1;
push @new_y, $y+1;
} else {
push @ret, 0,0;
}
}
@pending_x = @new_x;
@pending_y = @new_y;
}
return (@ret,
((0) x $#pending_x)); # pending open nodes
}
#------------------------------------------------------------------------------
# A001317 - rows as binary bignums, without the skipped (x^y)&1==1 points of
# triangular lattice
MyOEIS::compare_values
(anum => 'A001317',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'right');
my @got;
require Math::BigInt;
for (my $y = 0; @got < $count; $y++) {
my $b = 0;
foreach my $x (0 .. $y) {
if ($path->xy_is_visited($x,$y)) {
$b += Math::BigInt->new(2) ** $x;
}
}
push @got, "$b";
}
return \@got;
});
#------------------------------------------------------------------------------
# Dyck coded, depth-first
# A080263 sierpinski 2, 50, 906, 247986
# A080264 binary 10, 110010, 1110001010, 111100100010110010
# ( )
#
# * * * *
# \ / \ /
# * * * *
# \ / \ /
# * * * * * *
# \ / \ / \ /
# * * * *
# 10 110010 1,1100,0101,0 11,110010,0010,110010
# 10, 110010, 1110001010, 111100100010110010
# (())()
# [(())()]
# binary
MyOEIS::compare_values
(anum => 'A080264',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = dyck_tree_bits($path, 0,0, $depth);
push @got, _digit_join_hightolow(\@bits, 10, Math::BigInt->new(0));
}
return \@got;
});
# position in list of all balanced binary (A014486)
MyOEIS::compare_values
(anum => 'A080265',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = dyck_tree_bits($path, 0,0, $depth);
push @got, dyck_bits_to_index(\@bits);
}
return \@got;
});
# decimal
MyOEIS::compare_values
(anum => 'A080263',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = dyck_tree_bits($path, 0,0, $depth);
push @got, _digit_join_hightolow(\@bits, 2, Math::BigInt->new(0));
}
return \@got;
});
# No-such node = 0.
# Node = 1,left,right.
# Drop very last 0 at end.
#
sub dyck_tree_bits {
my ($path, $x,$y, $limit) = @_;
my @ret = dyck_tree_bits_z ($path, $x,$y, $limit);
pop @ret;
return @ret;
}
sub dyck_tree_bits_z {
my ($path, $x,$y, $limit) = @_;
if ($limit > 0 && $path->xy_is_visited($x,$y)) {
return (1,
dyck_tree_bits_z($path, $x-1,$y+1, $limit-1), # left
dyck_tree_bits_z($path, $x+1,$y+1, $limit-1)); # right
} else {
return (0);
}
}
# Doesn't distinguish left and right.
# sub parens_bits_z {
# my ($path, $x,$y, $limit) = @_;
# if ($limit > 0 && $path->xy_is_visited($x,$y)) {
# return (1,
# parens_bits_z($path, $x-1,$y+1, $limit-1), # left
# parens_bits_z($path, $x+1,$y+1, $limit-1), # right
# 0);
# } else {
# return ();
# }
# }
#------------------------------------------------------------------------------
# breath-wise "level-order"
#
# A080268 decimal 2, 56, 968, 249728, 3996680,
# A080269 binary 10, 111000, 1111001000, 111100111110000000, 1111001111110000001000,
# (( (()) () ))
#
# 111100111111000000111111001100111111111000000000000000
#
# cf A057118 permute depth<->breadth
#
# position in list of all balanced binary (A014486)
MyOEIS::compare_values
(anum => 'A080270',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = level_order_bits($path, $depth);
push @got, dyck_bits_to_index(\@bits);
}
return \@got;
});
# decimal
MyOEIS::compare_values
(anum => 'A080268',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = level_order_bits($path, $depth);
push @got, Math::BigInt->new("0b".join('',@bits));
}
return \@got;
});
# binary
MyOEIS::compare_values
(anum => 'A080269',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $depth = 1; @got < $count; $depth++) {
my @bits = level_order_bits($path, $depth);
push @got, _digit_join_hightolow(\@bits, 10, Math::BigInt->new(0));
}
return \@got;
});
# Return a list of 0,1 bits.
# No-such node = 0.
# Node = 1.
# Nodes descend to left,right breadth-wise in next level.
# Drop very last 0 at end.
#
sub level_order_bits {
my ($path, $limit) = @_;
my @pending_x = (0);
my @pending_y = (0);
my @ret;
foreach (1 .. $limit) {
my @new_x;
my @new_y;
foreach my $i (0 .. $#pending_x) {
my $x = $pending_x[$i];
my $y = $pending_y[$i];
if ($path->xy_is_visited($x,$y)) {
push @ret, 1;
push @new_x, $x-1;
push @new_y, $y+1;
push @new_x, $x+1;
push @new_y, $y+1;
} else {
push @ret, 0;
}
}
@pending_x = @new_x;
@pending_y = @new_y;
}
push @ret, (0) x (scalar(@pending_x)-1);
return @ret;
}
#------------------------------------------------------------------------------
# A106344 - by dX=-3,dY=+1 slopes upwards
# cf A106346 its matrix inverse, or something
#
# 1
# 0, 1
# 0, 1, 1,
# 0, 0, 0, 1,
# 0, 0, 1, 1, 1,
# 0, 0, 0, 1, 0, 1,
# 0, 0, 0, 1, 0, 1, 1,
# 0, 0, 0, 0, 0, 0, 0, 1,
# 0, 0, 0, 0, 1, 0, 1, 1, 1,
# 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
# 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1,
# 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
# 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1,
# 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1
# 19 20 21 22 23 24 25 26
# 15 16 17 18
# 11 12 13 14 .
# 9 10 .
# 5 6 7 8 .
# 3 . 4 .
# 1 2 . .
# 0 . . .
# path(x,y) = binomial(y,(x+y)/2)
# T(n,k)=binomial(k,n-k)
# y=k
# (x+y)/2=n-k
# x+k=2n-2k
# x=2n-3k
MyOEIS::compare_values
(anum => 'A106344',
func => sub {
my ($count) = @_;
# align="left" is dX=1,dY=1 diagonals
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'left');
my @got;
my $xstart = 0;
my $x = 0;
my $y = 0;
while (@got < $count) {
my $n = $path->xy_to_n($x,$y);
push @got, (defined $n ? 1 : 0);
$x += 1;
$y += 1;
if ($x > 0) {
$xstart--;
$x = $xstart;
$y = 0;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A106344},
func => sub {
my ($count) = @_;
# align="right" is dX=2,dY=1 slopes, chess knight moves
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'right');
my @got;
my $xstart = 0;
my $x = 0;
my $y = 0;
while (@got < $count) {
my $n = $path->xy_to_n($x,$y);
push @got, (defined $n ? 1 : 0);
$x += 2;
$y += 1;
if ($x > $y) {
$xstart--;
$x = $xstart;
$y = 0;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A106344},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
my $xstart = 0;
my $x = 0;
my $y = 0;
while (@got < $count) {
my $n = $path->xy_to_n($x,$y);
push @got, (defined $n ? 1 : 0);
$x += 3;
$y += 1;
if ($x > $y) {
$xstart -= 2;
$x = $xstart;
$y = 0;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A106344},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
OUTER: for (my $n = 0; ; $n++) {
for (my $k = 0; $k <= $n; $k++) {
my $n = $path->xy_to_n(2*$n-3*$k,$k);
push @got, (defined $n ? 1 : 0);
if (@got >= $count) {
last OUTER;
}
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A106344},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
require Math::BigInt;
OUTER: for (my $n = 0; ; $n++) {
for (my $k = 0; $k <= $n; $k++) {
# my $b = Math::BigInt->new($k);
# $b->bnok($n-$k); # binomial(k,k-n)
# $b->bmod(2);
# push @got, $b;
push @got, binomial_mod2 ($k, $n-$k);
if (@got >= $count) {
last OUTER;
}
}
}
return \@got;
});
# my $b = Math::BigInt->new($k);
# $b->bnok($n-$k); # binomial(k,k-n)
# $b->bmod(2);
sub binomial_mod2 {
my ($n, $k) = @_;
return Math::BigInt->new($n)->bnok($k)->bmod(2)->numify;
}
#------------------------------------------------------------------------------
# A106345 -
# k=0..floor(n/2) of binomial(k, n-2k)
#
# path(x,y) = binomial(y,(x+y)/2)
# T(n,k)=binomial(k,n-2k)
# y=k
# (x+y)/2=n-2k
# x+k=2n-4k
# x=2n-5k
MyOEIS::compare_values
(anum => 'A106345',
max_count => 1000, # touch slow, shorten
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
for (my $xstart = 0; @got < $count; $xstart -= 2) {
my $x = $xstart;
my $y = 0;
my $total = 0;
while ($x <= $y) {
my $n = $path->xy_to_n($x,$y);
if (defined $n) {
$total++;
}
$x += 5;
$y += 1;
}
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A002487 - stern diatomic count along of dX=3,dY=1 slopes
MyOEIS::compare_values
(anum => 'A002487',
max_count => 1000, # touch slow, shorten
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got = (0);
for (my $xstart = 0; @got < $count; $xstart -= 2) {
my $x = $xstart;
my $y = 0;
my $total = 0;
while ($x <= $y) {
my $n = $path->xy_to_n($x,$y);
if (defined $n) {
$total++;
}
$x += 3;
$y += 1;
}
push @got, $total;
}
return \@got;
});
#------------------------------------------------------------------------------
# A001316 - Gould's sequence, number of 1s in each row
MyOEIS::compare_values
(anum => 'A001316',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
my $prev_y = 0;
my $num = 0;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($y == $prev_y) {
$num++;
} else {
push @got, $num;
$prev_y = $y;
$num = 1;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A047999 - 1/0 by rows, without the skipped (x^y)&1==1 points of triangular
# lattice
MyOEIS::compare_values
(anum => 'A047999',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my @got;
my $x = 0;
my $y = 0;
foreach my $n (1 .. $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x += 2;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => q{A047999},
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new (align => "right");
my @got;
my $x = 0;
my $y = 0;
foreach my $n (1 .. $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = 0;
}
}
return \@got;
});
#------------------------------------------------------------------------------
# A075438 - 1/0 by rows of "right", including blank 0s in left of pyramid
MyOEIS::compare_values
(anum => 'A075438',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'right');
my @got;
my $x = 0;
my $y = 0;
foreach my $n (1 .. $count) {
push @got, ($path->xy_is_visited($x,$y) ? 1 : 0);
$x++;
if ($x > $y) {
$y++;
$x = -$y;
}
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/oeis/R5DragonCurve-oeis.t 0000644 0001750 0001750 00000003070 12136177277 017056 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::R5DragonCurve;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# A175337 -- turn 0=left,1=right
MyOEIS::compare_values
(anum => 'A175337',
func => sub {
my ($count) = @_;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'R5DragonCurve',
turn_type => 'Right');
my @got;
while (@got < $count) {
my ($i,$value) = $seq->next;
push @got, $value;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/KochCurve-more.t 0000644 0001750 0001750 00000006415 12136177167 015371 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::DragonCurve;
use Test;
plan tests => 1;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# rect_to_n_range() on various boxes
{
require Math::PlanePath::KochCurve;
my $path = Math::PlanePath::KochCurve->new;
my $n_start = $path->n_start;
my $bad = 0;
my $report = sub {
MyTestHelpers::diag (@_);
$bad++;
};
my $count = 0;
foreach my $y1 (-2 .. 10, 18, 30, 50, 100) {
foreach my $y2 ($y1 .. $y1 + 10) {
foreach my $x1 (-2 .. 10, 18, 30, 50, 100) {
my $min;
my $max;
foreach my $x2 ($x1 .. $x1 + 10) {
$count++;
my @col = map {$path->xy_to_n($x2,$_)} $y1 .. $y2;
@col = grep {defined} @col;
$min = List::Util::min (grep {defined} $min, @col);
$max = List::Util::max (grep {defined} $max, @col);
my $want_min = (defined $min ? $min : 1);
my $want_max = (defined $max ? $max : 0);
### @col
### rect: "$x1,$y1 $x2,$y2 expect N=$want_min..$want_max"
foreach my $x_swap (0, 1) {
my ($x1,$x2) = ($x_swap ? ($x1,$x2) : ($x2,$x1));
foreach my $y_swap (0, 1) {
my ($y1,$y2) = ($y_swap ? ($y1,$y2) : ($y2,$y1));
my ($got_min, $got_max)
= $path->rect_to_n_range ($x1,$y1, $x2,$y2);
defined $got_min
or &$report ("rect_to_n_range() got_min undef");
defined $got_max
or &$report ("rect_to_n_range() got_max undef");
$got_min >= $n_start
or &$report ("rect_to_n_range() got_min=$got_min is before n_start=$n_start");
if (! defined $min || ! defined $max) {
next; # outside
}
unless ($got_min == $want_min) {
&$report ("rect_to_n_range() bad min $x1,$y1 $x2,$y2 got_min=$got_min want_min=$want_min".(defined $min ? '' : '[nomin]')
);
}
unless ($got_max == $want_max) {
&$report ("rect_to_n_range() bad max $x1,$y1 $x2,$y2 got $got_max want $want_max".(defined $max ? '' : '[nomax]'));
}
}
}
}
}
}
}
MyTestHelpers::diag ("total $count rectangles");
ok (! $bad);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/MyOEIS.pm 0000644 0001750 0001750 00000047656 12255451035 013761 0 ustar gg gg # Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# MyOEIS.pm is shared by several distributions.
#
# MyOEIS.pm 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, or (at your option) any later
# version.
#
# MyOEIS.pm 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 file. If not, see .
package MyOEIS;
use strict;
use Carp;
use File::Spec;
# uncomment this to run the ### lines
# use Smart::Comments;
my $without;
sub import {
shift;
foreach (@_) {
if ($_ eq '-without') {
$without = 1;
} else {
die __PACKAGE__." unknown option $_";
}
}
}
sub read_values {
my ($anum, %option) = @_;
if ($without) {
return;
}
my @bvalues;
my $lo;
my $filename;
if (my $seq = eval { require Math::NumSeq::OEIS::File;
Math::NumSeq::OEIS::File->new (anum => $anum) }) {
my $count = 0;
if (($lo, my $value) = $seq->next) {
push @bvalues, $value;
while ((undef, $value) = $seq->next) {
push @bvalues, $value;
}
}
$filename = $seq->{'filename'};
} else {
my $error = $@;
@bvalues = Math::OEIS::Stripped->anum_to_values($anum);
if (! @bvalues) {
MyTestHelpers::diag ("$anum not available: ", $error);
return;
}
$filename = Math::OEIS::Stripped->filename;
}
my $desc = "$anum has ".scalar(@bvalues)." values";
if (@bvalues) { $desc .= " to $bvalues[-1]"; }
if (my $max_count = $option{'max_count'}) {
if (@bvalues > $max_count) {
$#bvalues = $option{'max_count'} - 1;
$desc .= ", shorten to ".scalar(@bvalues)." values to $bvalues[-1]";
}
}
if (my $max_value = $option{'max_value'}) {
if ($max_value ne 'unlimited') {
for (my $i = 0; $i <= $#bvalues; $i++) {
if ($bvalues[$i] > $max_value) {
$#bvalues = $i-1;
if (@bvalues) {
$desc .= ", shorten to ".scalar(@bvalues)." values to $bvalues[-1]";
} else {
$desc .= ", shorten to nothing";
}
}
}
}
}
MyTestHelpers::diag ($desc);
return (\@bvalues, $lo, $filename);
}
sub oeis_directory {
# my ($class) = @_;
require File::HomeDir;
my $dir = File::HomeDir->my_home;
if (! defined $dir) {
die 'File::HomeDir says you have no home directory';
}
require File::Spec;
return File::Spec->catdir($dir, 'OEIS');
}
# with Y reckoned increasing downwards
sub dxdy_to_direction {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # south
if ($dy < 0) { return 3; } # north
}
# Search for a line in text file handle $fh.
# $cmpfunc is called &$cmpfunc($line) and it should do a
# comparison $target <=> $line so
# 0 if $target == $line
# -ve if $target < $line so $line is after the target
# +ve if $target > $line so $line is before the target
sub bsearch_textfile {
my ($fh, $cmpfunc) = @_;
my $lo = 0;
my $hi = -s $fh;
for (;;) {
my $mid = ($lo+$hi)/2;
seek $fh, $mid, 0
or last;
# skip partial line
defined(readline $fh)
or last; # EOF
# position start of line
$mid = tell($fh);
if ($mid >= $hi) {
last;
}
my $line = readline $fh;
defined $line
or last; # EOF
my $cmp = &$cmpfunc ($line);
if ($cmp == 0) {
return $line;
}
if ($cmp < 0) {
$lo = tell($fh); # $line is before the target, advance $lo
} else {
$hi = $mid; # $line is after the target, reduce $hi
}
}
seek $fh, $lo, 0;
while (defined (my $line = readline $fh)) {
my $cmp = &$cmpfunc($line);
if ($cmp == 0) {
return $line;
}
if ($cmp > 0) {
return undef;
}
}
return undef;
}
sub compare_values {
my %option = @_;
require MyTestHelpers;
my $anum = $option{'anum'} || croak "Missing anum parameter";
my $func = $option{'func'} || croak "Missing func parameter";
my ($bvalues, $lo, $filename) = MyOEIS::read_values
($anum,
max_count => $option{'max_count'},
max_value => $option{'max_value'});
my $diff;
if ($bvalues) {
if (my $fixup = $option{'fixup'}) {
&$fixup($bvalues);
}
my ($got,@rest) = &$func(scalar(@$bvalues));
if (@rest) {
croak "Oops, func return more than just an arrayref";
}
if (ref $got ne 'ARRAY') {
croak "Oops, func return not an arrayref";
}
$diff = diff_nums($got, $bvalues);
if ($diff) {
MyTestHelpers::diag ("bvalues: ",join_values($bvalues));
MyTestHelpers::diag ("got: ",join_values($got));
}
}
if (defined $Test::TestLevel) {
require Test;
local $Test::TestLevel = $Test::TestLevel + 1;
Test::skip (! $bvalues, $diff, undef, "$anum");
} elsif (defined $diff) {
print "$diff\n";
}
}
sub join_values {
my ($aref) = @_;
if (! @$aref) { return ''; }
my $str = $aref->[0];
foreach my $i (1 .. $#$aref) {
my $value = $aref->[$i];
if (! defined $value) { $value = 'undef'; }
last if length($str)+1+length($value) >= 275;
$str .= ',';
$str .= $value;
}
return $str;
}
sub diff_nums {
my ($gotaref, $wantaref) = @_;
my $diff;
for (my $i = 0; $i < @$gotaref; $i++) {
if ($i > @$wantaref) {
return "want ends prematurely pos=$i";
}
my $got = $gotaref->[$i];
my $want = $wantaref->[$i];
if (! defined $got && ! defined $want) {
next;
}
if (defined $got != defined $want) {
if (defined $diff) {
return "$diff, and more diff";
}
$diff = "different pos=$i got=".(defined $got ? $got : '[undef]')
." want=".(defined $want ? $want : '[undef]');
}
unless ($got =~ /^[0-9.-]+$/) {
if (defined $diff) {
return "$diff, and more diff";
}
$diff = "not a number pos=$i got='$got'";
}
unless ($want =~ /^[0-9.-]+$/) {
if (defined $diff) {
return "$diff, and more diff";
}
$diff = "not a number pos=$i want='$want'";
}
if ($got != $want) {
if (defined $diff) {
return "$diff, and more diff";
}
$diff = "different pos=$i numbers got=$got want=$want";
}
}
return $diff;
}
# counting from 1 for prime=2
sub ith_prime {
my ($i) = @_;
if ($i < 1) {
croak "Oops, ith_prime() i=$i";
}
require Math::Prime::XS;
my $to = 100;
for (;;) {
my @primes = Math::Prime::XS::primes($to);
if (@primes >= $i) {
return $primes[$i-1];
}
$to *= 2;
}
}
sub grep_for_values_aref {
my ($class, $aref) = @_;
MyOEIS->grep_for_values(array => $aref);
}
sub grep_for_values {
my ($class, %h) = @_;
### grep_for_values_aref() ...
### $class
my $name = $h{'name'};
if (defined $name) {
$name = "$name: ";
}
my $values_aref = $h{'array'};
if (@$values_aref == 0) {
### empty ...
return "${name}no match empty list of values\n\n";
}
{
my $join = $values_aref->[0];
for (my $i = 1; $i <= $#$values_aref && length($join) < 50; $i++) {
$join .= ','.$values_aref->[$i];
}
$name .= "match $join\n";
}
if (defined (my $value = constant_array(@$values_aref))) {
return '';
if ($value != 0) {
return "${name}constant $value\n\n";
}
}
if (defined (my $diff = constant_diff(@$values_aref))) {
return "${name}constant difference $diff\n\n";
}
my $values_str = join (',',@$values_aref);
# print "grep $values_str\n";
# unless (system 'zgrep', '-F', '-e', $values_str, "$ENV{HOME}/OEIS/stripped.gz") {
# print " match $values_str\n";
# print " $name\n";
# print "\n"
# }
# unless (system 'fgrep', '-e', $values_str, "$ENV{HOME}/OEIS/oeis-grep.txt") {
# print " match $values_str\n";
# print " $name\n";
# print "\n"
# }
# unless (system 'fgrep', '-e', $values_str, "$ENV{HOME}/OEIS/stripped") {
# print " match $values_str\n";
# print " $name\n";
# print "\n"
# }
if (my $str = $class->stripped_grep($values_str)) {
return "$name$str\n";
}
}
use constant GREP_MAX_COUNT => 8;
my $stripped_mmap;
sub stripped_grep {
my ($class, $str) = @_;
if (! defined $stripped_mmap) {
my $stripped_filename = Math::OEIS::Stripped->filename;
require File::Map;
File::Map::map_file ($stripped_mmap, $stripped_filename);
print "File::Map stripped file length ",length($stripped_mmap),"\n";
}
my $ret = '';
my $count = 0;
# my $re = $str;
# { my $count = ($re =~ s{,}{,(\n|}g);
# $re .= ')'x$count;
# }
# ### $re
my $orig_str = $str;
my $abs = '';
foreach my $mung ('none', 'negate', 'abs', 'half') {
if ($ret) { last; }
if ($mung eq 'none') {
} elsif ($mung eq 'negate') {
$abs = "[NEGATED]\n";
$str = $orig_str;
$str =~ s{(^|,)(-?)}{$1.($2?'':'-')}ge;
} elsif ($mung eq 'half') {
if ($str =~ /[13579](,|$)/) {
### not all even to halve ...
next;
}
$str = join (',', map {$_/2} split /,/, $orig_str);
$abs = "[HALF]\n";
} elsif ($mung eq 'abs') {
$str = $orig_str;
if (! ($str =~ s/-//g)) {
### no negatives to absolute ...
next;
}
if ($str =~ /^(\d+)(,\1)*$/) {
### only one value when abs: $1
next;
}
$abs = "[ABSOLUTE VALUES]\n";
}
### $str
my $pos = 0;
for (;;) {
my $found_pos = index($stripped_mmap,$str,$pos);
### $found_pos
last if $found_pos < 0;
unless (substr($stripped_mmap,$found_pos-1,1) =~ / |,/) {
$pos = $found_pos+1;
next;
}
if ($count >= GREP_MAX_COUNT) {
$ret .= "... and more matches\n";
return $ret;
}
my $start = rindex($stripped_mmap,"\n",$found_pos) + 1;
my $end = index($stripped_mmap,"\n",$found_pos);
my $line = substr($stripped_mmap,$start,$end-$start);
my ($anum) = ($line =~ /^(A\d+)/);
$anum || die "oops, A-number not matched in line: ",$line;
my $name = Math::OEIS::Names->anum_to_name($anum);
if (! defined $name) { $name = '[name not found]'; }
$ret .= $abs; $abs = '';
$ret .= "$anum $name\n";
$ret .= "$line\n";
$pos = $end;
$count++;
}
}
return $ret;
}
# constant_diff($a,$b,$c,...)
# If all the given values have a constant difference then return that amount.
# Otherwise return undef.
#
sub constant_diff {
my $diff = shift;
my $value = shift;
$diff = $value - $diff;
while (@_) {
my $next_value = shift;
if ($next_value - $value != $diff) {
return undef;
}
$value = $next_value;
}
return $diff;
}
# constant_array($a,$b,$c,...)
# If all the given values are all equal then return that value.
# Otherwise return undef.
#
sub constant_array {
my $value = shift;
while (@_) {
my $next_value = shift;
if ($next_value != $value) {
return undef;
}
}
return $value;
}
#------------------------------------------------------------------------------
=head1 FUNCTIONS
=over
=item C<$mon = Math::OEIS::Names-Enew(key =E value, ...)>
Create and return a new C object to read an OEIS "names"
file. The optional key/value parameters can be
filename => $filename default ~/OEIS/names
fh => $filehandle
The default filename is F<~/OEIS/names>, so the F directory under the
user's home directory. A different filename can be given, or an open
filehandle can be given.
=item C<$name = Math::OEIS::Names-Eanum_to_name($anum)>
For a given C<$anum> string such as "A000001" return the sequence name
as a string, or if not found then C.
=item C<$filename = $mon-Efilename()>
=item C<$filename = Math::OEIS::Names-Efilename()>
Return the names filename from a given C<$mon> object, or the default
filename if called as a class method C.
=back
=head2 BUGS
The current implementation is a text file binary search. For large numbers
of name lookups an actual database would probably be more efficient.
Perhaps C could automatically look in an SQLite or
similar database if it exists and is up-to-date.
=cut
{
package Math::OEIS::Names;
use strict;
use Carp 'croak';
use Search::Dict;
use File::Spec;
use base 'Class::Singleton';
*_new_instance = \&new;
sub new {
my $class = shift;
return bless { @_ }, $class;
}
sub default_filename {
my ($class) = @_;
return File::Spec->catfile (MyOEIS->oeis_directory(), 'names');
}
sub filename {
my ($self) = @_;
if (ref $self && defined $self->{'filename'}) {
return $self->{'filename'};
}
return $self->default_filename;
}
sub fh {
my ($self) = @_;
return ($self->{'fh'} ||= do {
my $filename = $self->filename;
open my $fh, '<', $filename
or croak "Cannot open ",$filename,": ",$!;
$fh
});
}
# return A-number string, or undef
sub line_to_anum {
my ($line) = @_;
$line =~ s/^(A\d+).*/$1/
or return ''; # comment lines
return $line
}
# C<($anum,$name) = Math::OEIS::Names-Eline_split($line)>
# Split a line from the names file into A-number and name.
sub line_split {
my ($self, $line) = @_;
### Names line_split(): $line
$line =~ /^(A\d+)\s*(.*)/
or return; # perhaps comment lines
return ($1, $2)
}
sub anum_to_name {
my ($self, $anum) = @_;
### $anum
if (! ref $self) { $self = $self->instance; }
my $fh = $self->fh || return undef;
my $pos = Search::Dict::look ($fh, $anum,
{ xfrm => sub {
my ($line) = @_;
### $line
my ($got_anum) = $self->line_split($line)
or return '';
### $got_anum
return $got_anum;
} });
if ($pos < 0) { croak 'Error reading names file: ',$!; }
my $line = readline $fh;
if (! defined $line) { return undef; }
my ($got_anum, $name) = $self->line_split($line);
if ($got_anum ne $anum) { return undef; }
return $name;
}
}
# sub anum_to_name {
# my ($class, $anum) = @_;
# $anum =~ /^A[0-9]+$/ or die "Bad A-number: ", $anum;
# return `zgrep -e ^$anum $ENV{HOME}/OEIS/names.gz`;
# }
#------------------------------------------------------------------------------
=head1 FUNCTIONS
=over
=item C<$mos = Math::OEIS::Stripped-Enew(key =E value, ...)>
Create and return a new C object to read an OEIS
"stripped" file. The optional key/value parameters can be
filename => $filename default ~/OEIS/stripped
fh => $filehandle
The default filename is F<~/OEIS/stripped>, so in an F directory in
the user's home directory. A different filename can be given, or an open
filehandle can be given.
=item C<@values = Math::OEIS::Stripped-Eanum_to_values($anum)>
=item C<$str = Math::OEIS::Stripped-Eanum_to_values_str($anum)>
Return the values from the stripped file for given C<$anum> (a string such
as "A000001").
C returns a list of values, or no values if not found.
C returns a string like "1,2,3,4" or C if not
found.
The stripped file has a leading comma on its values list, but this is
removed from C for convenience of subsequent C
or similar.
Draft sequences have an empty values list ",,". The return for them is the
same as "not found", reckoning that it doesn't exist yet.
=item C<$filename = $mos-Efilename()>
=item C<$filename = Math::OEIS::Stripped-Efilename()>
Return the stripped filename from a given C<$mos> object, or the default
filename if called as a class method C.
=back
=cut
{
package Math::OEIS::Stripped;
use strict;
use Carp 'croak';
use Search::Dict;
use File::Spec;
use base 'Class::Singleton';
*_new_instance = \&new;
sub new {
my $class = shift;
return bless { use_bigint => 'if_needed',
@_ }, $class;
}
sub default_filename {
my ($class) = @_;
return File::Spec->catfile (MyOEIS->oeis_directory(), 'stripped');
}
sub filename {
my ($self) = @_;
if (ref $self && defined $self->{'filename'}) {
return $self->{'filename'};
}
return $self->default_filename;
}
sub fh {
my ($self) = @_;
return ($self->{'fh'} ||= do {
my $filename = $self->filename;
open my $fh, '<', $filename
or croak "Cannot open ",$filename,": ",$!;
$fh
});
}
sub anum_to_values {
my ($self, $anum) = @_;
if (! ref $self) { $self = $self->instance; }
my @values;
my $values_str = $self->anum_to_values_str($anum);
if (defined $values_str) {
@values = split /,/, $values_str;
if ($self->{'use_bigint'}) {
my $bigint_class = $self->bigint_class_load;
foreach my $value (@values) {
unless ($self->{'use_bigint'} eq 'if_needed'
&& length($value) < 10) {
$value = Math::BigInt->new($value); # mutate array
}
}
}
}
return @values;
}
sub bigint_class_load {
my ($self) = @_;
return ($self->{'bigint_class_load'} ||= do {
require Module::Load;
my $bigint_class = $self->bigint_class;
Module::Load::load($bigint_class);
### $bigint_class
$bigint_class
});
}
sub bigint_class {
my ($self) = @_;
return ($self->{'bigint_class'} ||= do {
require Math::BigInt;
eval { Math::BigInt->import (try => 'GMP') };
'Math::BigInt'
});
}
sub anum_to_values_str {
my ($self, $anum) = @_;
### anum_to_values_str(): $anum
if (! ref $self) { $self = $self->instance; }
my $fh = $self->fh || return undef;
my $pos = Search::Dict::look
($fh, $anum,
{ xfrm => sub {
my ($line) = @_;
return ($self->line_to_anum($line) || '');
} });
if ($pos < 0) { croak 'Error reading stripped file: ',$!; }
my $line = readline $fh;
if (! defined $line) { return undef; }
my ($got_anum, $values_str) = $self->line_split_anum($line);
if ($got_anum ne $anum) { return undef; }
return $values_str;
}
# C<$anum = Math::OEIS::Stripped-Eline_split_anum($line)>
#
# $line is a line from the stripped file. Return the A-number string from
# the line such as "A000001", or C if unrecognised or a comment
# line etc.
#
sub line_to_anum {
my ($self, $line) = @_;
### $line
$line =~ s/^(A\d+).*/$1/
or return ''; # comment lines
return $line
}
# C<($anum,$values_str) = Math::OEIS::Stripped-Eline_split_anum($line)>
#
# Split a line from the stripped file into A-number and values string.
# Any leading comma like ",1,2,3" is removed from $values_str.
#
# If C<$line> is a comment or unrecognised then return no values.
#
sub line_split_anum {
my ($self, $line) = @_;
### Stripped line_split_anum(): $line
$line =~ /^(A\d+)\s*,?([0-9].*)/
or return; # comment lines or empty
return ($1, $2)
}
# # return list of values, or empty list if not found
# sub stripped_read_values {
# my ($class, $anum) = @_;
# open FH, "< " . __PACKAGE__->stripped_filename
# or return;
# (my $num = $anum) =~ s/^A//;
# my $line = bsearch_textfile (\*FH, sub {
# my ($line) = @_;
# $line =~ /^A(\d+)/ or return -1;
# return ($1 <=> $num);
# })
# || return;
#
# $line =~ s/A\d+ *,?//;
# $line =~ s/\s+$//;
# return split /,/, $line;
# }
}
#------------------------------------------------------------------------------
# my @values = Math::OEIS::Stripped->anum_to_values('A000129');
# ### @values
1;
__END__
Math-PlanePath-113/xt/0-examples-xrefs.t 0000644 0001750 0001750 00000004300 12230011245 015602 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2013 Kevin Ryde
# 0-examples-xrefs.t is shared by several distributions.
#
# 0-examples-xrefs.t 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, or (at your option) any
# later version.
#
# 0-examples-xrefs.t 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 file. If not, see .
BEGIN { require 5 }
use strict;
use ExtUtils::Manifest;
use Test::More;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
my $manifest = ExtUtils::Manifest::maniread();
my @example_files = grep m{examples/.*\.pl$}, keys %$manifest;
my @lib_files = grep m{lib/.*\.(pm|pod)$}, keys %$manifest;
sub any_file_contains_example {
my ($example) = @_;
my $filename;
foreach $filename (@lib_files) {
if (pod_contains_example($filename, $example)) {
return 1;
}
}
foreach $filename (@example_files) {
if ($filename ne $example
&& raw_contains_example($filename, $example)) {
return 1;
}
}
return 0;
}
sub pod_contains_example {
my ($filename, $example) = @_;
open FH, "< $filename" or die "Cannot open $filename: $!";
my $content = do { local $/; }; # slurp
close FH or die "Error closing $filename: $!";
return scalar ($content =~ /F<\Q$example\E>
|F\s+directory
/xs);
}
sub raw_contains_example {
my ($filename, $example) = @_;
$example =~ s{^examples/}{};
open FH, "< $filename" or die "Cannot open $filename: $!";
my $ret = scalar (grep /\b\Q$example\E\b/, );
close FH or die "Error closing $filename: $!";
return $ret > 0;
}
plan tests => scalar(@example_files) + 1;
my $example;
foreach $example (@example_files) {
is (any_file_contains_example($example), 1,
"$example mentioned in some lib/ file");
}
ok(1);
exit 0;
Math-PlanePath-113/xt/PlanePath-subclasses.t 0000644 0001750 0001750 00000274312 12253151312 016544 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Exercise the various PlanePath subclasses checking for consistency between
# n_to_xy() and xy_to_n() and the various range methods, etc.
#
use 5.004;
use strict;
use List::Util;
use Test;
plan tests => 5;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
# use Smart::Comments;
use Math::PlanePath;
use Math::PlanePath::Base::Generic
'is_infinite';
use Math::PlanePath::Base::Digits
'round_down_pow';
my $verbose = 1;
my @modules = (
# modules marked "*" are from Math-PlanePath-Toothpick or
# elsewhere and are skipped if not available to test
# module list begin
'*HTree',
'PythagoreanTree,tree_type=UMT',
'PythagoreanTree,tree_type=UMT,coordinates=AC',
'PythagoreanTree,tree_type=UMT,coordinates=BC',
'PythagoreanTree,tree_type=UMT,coordinates=PQ',
'PythagoreanTree,tree_type=UMT,coordinates=SM',
'PythagoreanTree,tree_type=UMT,coordinates=SC',
'PythagoreanTree,tree_type=UMT,coordinates=MC',
'PythagoreanTree',
'PythagoreanTree,coordinates=AC',
'PythagoreanTree,coordinates=BC',
'PythagoreanTree,coordinates=PQ',
'PythagoreanTree,coordinates=SM',
'PythagoreanTree,coordinates=SC',
'PythagoreanTree,coordinates=MC',
'PythagoreanTree,tree_type=FB',
'PythagoreanTree,tree_type=FB,coordinates=AC',
'PythagoreanTree,tree_type=FB,coordinates=BC',
'PythagoreanTree,tree_type=FB,coordinates=PQ',
'PythagoreanTree,tree_type=FB,coordinates=SM',
'PythagoreanTree,tree_type=FB,coordinates=SC',
'PythagoreanTree,tree_type=FB,coordinates=MC',
'FactorRationals,sign_encoding=revbinary',
'FactorRationals',
'FactorRationals,sign_encoding=odd/even',
'FactorRationals,sign_encoding=negabinary',
'FactorRationals,sign_encoding=spread',
'*ToothpickUpist',
'SierpinskiTriangle',
'SierpinskiTriangle,n_start=37',
'SierpinskiTriangle,align=left',
'SierpinskiTriangle,align=right',
'SierpinskiTriangle,align=diagonal',
'DragonCurve',
'DragonCurve,arms=2',
'DragonCurve,arms=3',
'DragonCurve,arms=4',
'DragonMidpoint',
'DragonMidpoint,arms=2',
'DragonMidpoint,arms=3',
'DragonMidpoint,arms=4',
'DragonRounded',
'DragonRounded,arms=2',
'DragonRounded,arms=3',
'DragonRounded,arms=4',
'TerdragonMidpoint',
'TerdragonMidpoint,arms=2',
'TerdragonMidpoint,arms=3',
'TerdragonMidpoint,arms=6',
'TerdragonCurve',
'TerdragonCurve,arms=2',
'TerdragonCurve,arms=3',
'TerdragonCurve,arms=6',
'TerdragonRounded',
'TerdragonRounded,arms=2',
'TerdragonRounded,arms=3',
'TerdragonRounded,arms=4',
'TerdragonRounded,arms=5',
'TerdragonRounded,arms=6',
'R5DragonMidpoint',
'R5DragonMidpoint,arms=2',
'R5DragonMidpoint,arms=3',
'R5DragonMidpoint,arms=4',
'R5DragonCurve',
'R5DragonCurve,arms=2',
'R5DragonCurve,arms=3',
'R5DragonCurve,arms=4',
'KochCurve',
'KochPeaks',
'KochSnowflakes',
'KochSquareflakes',
'KochSquareflakes,inward=>1',
'VogelFloret',
'MultipleRings,ring_shape=polygon,step=3',
'MultipleRings,ring_shape=polygon,step=5',
'MultipleRings,ring_shape=polygon,step=6',
'MultipleRings,ring_shape=polygon,step=7',
'MultipleRings,ring_shape=polygon,step=8',
'MultipleRings,ring_shape=polygon,step=37',
'MultipleRings',
'MultipleRings,step=0',
'MultipleRings,step=1',
'MultipleRings,step=2',
'MultipleRings,step=3',
'MultipleRings,step=5',
'MultipleRings,step=6',
'MultipleRings,step=7',
'MultipleRings,step=8',
'MultipleRings,step=37',
'ArchimedeanChords',
# '*OneOfEight,parts=side',
'*OneOfEight,parts=3mid',
'*OneOfEight,parts=3side',
'*OneOfEight',
'*OneOfEight,parts=1',
'*OneOfEight,parts=octant',
'*OneOfEight,parts=octant_up',
'*OneOfEight,parts=wedge',
'*ToothpickTree,parts=wedge',
'*ToothpickTree,parts=two_horiz',
'*ToothpickTree,parts=octant',
'*ToothpickTree,parts=octant_up',
'*ToothpickTree',
'*ToothpickTree,parts=1',
'*ToothpickTree,parts=2',
'*ToothpickTree,parts=3',
'MPeaks',
'MPeaks,n_start=0',
'MPeaks,n_start=37',
'PyramidSides',
'PyramidSides,n_start=0',
'PyramidSides,n_start=37',
'Diagonals',
'Diagonals,direction=up',
'Diagonals,n_start=0',
'Diagonals,direction=up,n_start=0',
'Diagonals,n_start=37',
'Diagonals,direction=up,n_start=37',
'Diagonals,x_start=5',
'Diagonals,direction=up,x_start=5',
'Diagonals,x_start=2,y_start=5',
'Diagonals,direction=up,x_start=2,y_start=5',
'DiagonalsAlternating',
'DiagonalsAlternating,n_start=0',
'DiagonalsAlternating,n_start=37',
'DiagonalsAlternating,x_start=5',
'DiagonalsAlternating,x_start=2,y_start=5',
'AztecDiamondRings',
'AztecDiamondRings,n_start=0',
'AztecDiamondRings,n_start=37',
'PyramidSpiral',
'PyramidSpiral,n_start=0',
'PyramidSpiral,n_start=37',
'HeptSpiralSkewed',
'HeptSpiralSkewed,n_start=0',
'HeptSpiralSkewed,n_start=37',
'PentSpiral',
'PentSpiral,n_start=0',
'PentSpiral,n_start=37',
'PentSpiralSkewed',
'PentSpiralSkewed,n_start=0',
'PentSpiralSkewed,n_start=37',
'KnightSpiral',
'KnightSpiral,n_start=0',
'KnightSpiral,n_start=37',
'Staircase',
'Staircase,n_start=0',
'Staircase,n_start=37',
'StaircaseAlternating',
'StaircaseAlternating,n_start=0',
'StaircaseAlternating,n_start=37',
'StaircaseAlternating,end_type=square',
'StaircaseAlternating,end_type=square,n_start=0',
'StaircaseAlternating,end_type=square,n_start=37',
'OctagramSpiral',
'OctagramSpiral,n_start=0',
'OctagramSpiral,n_start=37',
'CornerReplicate',
'UlamWarburton',
'UlamWarburton,n_start=0',
'UlamWarburton,n_start=0,parts=2',
'UlamWarburton,n_start=0,parts=1',
'UlamWarburton,n_start=37',
'UlamWarburton,n_start=37,parts=2',
'UlamWarburton,n_start=37,parts=1',
'UlamWarburton,parts=2',
'UlamWarburton,parts=1',
'UlamWarburtonQuarter',
'UlamWarburtonQuarter,n_start=0',
'UlamWarburtonQuarter,n_start=37',
'RationalsTree',
'RationalsTree,tree_type=CW',
'RationalsTree,tree_type=AYT',
'RationalsTree,tree_type=Bird',
'RationalsTree,tree_type=Drib',
'RationalsTree,tree_type=L',
'RationalsTree,tree_type=HCS',
'*LCornerTree,parts=octant_up+1',
'*LCornerTree,parts=octant+1',
'*LCornerTree,parts=wedge+1',
'*LCornerTree,parts=diagonal-1',
'*LCornerTree,parts=diagonal',
'*LCornerTree,parts=wedge',
'*LCornerTree,parts=octant_up',
'*LCornerTree,parts=octant',
'*LCornerTree', # parts=4
'*LCornerTree,parts=1',
'*LCornerTree,parts=2',
'*LCornerTree,parts=3',
'*ToothpickSpiral',
'*ToothpickSpiral,n_start=0',
'*ToothpickSpiral,n_start=37',
# '*PeninsulaBridge',
'*ToothpickReplicate',
'*ToothpickReplicate,parts=1',
'*ToothpickReplicate,parts=2',
'*ToothpickReplicate,parts=3',
'*LCornerReplicate',
'ChanTree',
'ChanTree,n_start=1234',
'ChanTree,k=2',
'ChanTree,k=2,n_start=1234',
'ChanTree,k=4',
'ChanTree,k=5',
'ChanTree,k=7',
'ChanTree,reduced=1',
'ChanTree,reduced=1,k=2',
'ChanTree,reduced=1,k=4',
'ChanTree,reduced=1,k=5',
'ChanTree,reduced=1,k=7',
'DiagonalRationals',
'DiagonalRationals,n_start=37',
'DiagonalRationals,direction=up',
'DiagonalRationals,direction=up,n_start=37',
'PyramidRows,align=right',
'PyramidRows,align=right,step=0',
'PyramidRows,align=right,step=1',
'PyramidRows,align=right,step=3',
'PyramidRows,align=right,step=4',
'PyramidRows,align=right,step=5',
'PyramidRows,align=right,step=37',
'PyramidRows,align=left',
'PyramidRows,align=left,step=0',
'PyramidRows,align=left,step=1',
'PyramidRows,align=left,step=3',
'PyramidRows,align=left,step=4',
'PyramidRows,align=left,step=5',
'PyramidRows,align=left,step=37',
'PyramidRows',
'PyramidRows,step=0',
'PyramidRows,step=1',
'PyramidRows,step=3',
'PyramidRows,step=4',
'PyramidRows,step=5',
'PyramidRows,step=37',
'PyramidRows,step=0,n_start=37',
'PyramidRows,step=1,n_start=37',
'PyramidRows,step=2,n_start=37',
'PyramidRows,align=right,step=5,n_start=37',
'PyramidRows,align=left,step=3,n_start=37',
# Math::PlanePath::CellularRule::Line
'CellularRule,rule=2', # left line
'CellularRule,rule=2,n_start=0',
'CellularRule,rule=2,n_start=37',
'CellularRule,rule=4', # centre line
'CellularRule,rule=4,n_start=0',
'CellularRule,rule=4,n_start=37',
'CellularRule,rule=16', # right line
'CellularRule,rule=16,n_start=0',
'CellularRule,rule=16,n_start=37',
'CellularRule,rule=6', # left 1,2 line
'CellularRule,rule=6,n_start=0',
'CellularRule,rule=6,n_start=37',
'CellularRule,rule=20', # right 1,2 line
'CellularRule,rule=20,n_start=0',
'CellularRule,rule=20,n_start=37',
'CellularRule54',
'CellularRule54,n_start=0',
'CellularRule54,n_start=37',
'CellularRule57',
'CellularRule57,n_start=0',
'CellularRule57,n_start=37',
'CellularRule57,mirror=1',
'CellularRule57,mirror=1,n_start=0',
'CellularRule57,mirror=1,n_start=37',
'CellularRule190',
'CellularRule190,n_start=0',
'CellularRule190,n_start=37',
'CellularRule190,mirror=1',
'CellularRule190,mirror=1,n_start=0',
'CellularRule190,mirror=1,n_start=37',
'CellularRule',
'CellularRule,n_start=0',
'CellularRule,n_start=37',
'CellularRule,rule=206', # left solid
'CellularRule,rule=206,n_start=0',
'CellularRule,rule=206,n_start=37',
'CellularRule,rule=18', # Sierpinski
'CellularRule,rule=18,n_start=0',
'CellularRule,rule=18,n_start=37',
'CellularRule,rule=14', # left 2 cell line
'CellularRule,rule=14,n_start=0',
'CellularRule,rule=14,n_start=37',
'CellularRule,rule=84', # right 2 cell line
'CellularRule,rule=84,n_start=0',
'CellularRule,rule=84,n_start=37',
'CellularRule,rule=0', # blank
'CellularRule,rule=60',
'CellularRule,rule=220', # right half solid
'CellularRule,rule=222', # full solid
'PeanoCurve',
'PeanoCurve,radix=2',
'PeanoCurve,radix=4',
'PeanoCurve,radix=5',
'PeanoCurve,radix=17',
'TriangleSpiralSkewed',
'TriangleSpiralSkewed,n_start=0',
'TriangleSpiralSkewed,n_start=37',
'TriangleSpiralSkewed,skew=right',
'TriangleSpiralSkewed,skew=right,n_start=0',
'TriangleSpiralSkewed,skew=right,n_start=37',
'TriangleSpiralSkewed,skew=up',
'TriangleSpiralSkewed,skew=up,n_start=0',
'TriangleSpiralSkewed,skew=up,n_start=37',
'TriangleSpiralSkewed,skew=down',
'TriangleSpiralSkewed,skew=down,n_start=0',
'TriangleSpiralSkewed,skew=down,n_start=37',
'TriangleSpiral',
'TriangleSpiral,n_start=0',
'TriangleSpiral,n_start=37',
'WythoffArray',
'WythoffArray,x_start=1',
'WythoffArray,y_start=1',
'WythoffArray,x_start=1,y_start=1',
'WythoffArray,x_start=5,y_start=7',
'HexSpiral',
'HexSpiral,n_start=0',
'HexSpiral,n_start=37',
'HexSpiral,wider=10,n_start=37',
'HexSpiral,wider=1',
'HexSpiral,wider=2',
'HexSpiral,wider=3',
'HexSpiral,wider=4',
'HexSpiral,wider=5',
'HexSpiral,wider=37',
'HexSpiralSkewed',
'HexSpiralSkewed,n_start=0',
'HexSpiralSkewed,n_start=37',
'HexSpiralSkewed,wider=10,n_start=37',
'HexSpiralSkewed,wider=1',
'HexSpiralSkewed,wider=2',
'HexSpiralSkewed,wider=3',
'HexSpiralSkewed,wider=4',
'HexSpiralSkewed,wider=5',
'HexSpiralSkewed,wider=37',
'Rows',
'Rows,width=1',
'Rows,width=2',
'Rows,n_start=0',
'Rows,width=37,n_start=0',
'Rows,width=37,n_start=123',
'Columns',
'Columns,height=1',
'Columns,height=2',
'Columns,n_start=0',
'Columns,height=37,n_start=0',
'Columns,height=37,n_start=123',
'CoprimeColumns',
'CoprimeColumns,n_start=37',
'DivisibleColumns',
'DivisibleColumns,n_start=37',
'DivisibleColumns,divisor_type=proper',
'FilledRings',
'FilledRings,n_start=0',
'FilledRings,n_start=37',
'AnvilSpiral,n_start=0',
'AnvilSpiral,n_start=37',
'AnvilSpiral,n_start=37,wider=9',
'AnvilSpiral,wider=17',
'AnvilSpiral',
'AnvilSpiral,wider=1',
'AnvilSpiral,wider=2',
'AnvilSpiral,wider=9',
'AnvilSpiral,wider=17',
'Flowsnake',
'Flowsnake,arms=2',
'Flowsnake,arms=3',
'FlowsnakeCentres',
'FlowsnakeCentres,arms=2',
'FlowsnakeCentres,arms=3',
'SierpinskiCurve',
'SierpinskiCurve,diagonal_spacing=5',
'SierpinskiCurve,straight_spacing=5',
'SierpinskiCurve,diagonal_spacing=3,straight_spacing=7',
'SierpinskiCurve,diagonal_spacing=3,straight_spacing=7,arms=7',
'SierpinskiCurve,arms=2',
'SierpinskiCurve,arms=3',
'SierpinskiCurve,arms=4',
'SierpinskiCurve,arms=5',
'SierpinskiCurve,arms=6',
'SierpinskiCurve,arms=7',
'SierpinskiCurve,arms=8',
'SierpinskiCurveStair',
'SierpinskiCurveStair,diagonal_length=2',
'SierpinskiCurveStair,diagonal_length=3',
'SierpinskiCurveStair,diagonal_length=4',
'SierpinskiCurveStair,arms=2',
'SierpinskiCurveStair,arms=3,diagonal_length=2',
'SierpinskiCurveStair,arms=4',
'SierpinskiCurveStair,arms=5',
'SierpinskiCurveStair,arms=6,diagonal_length=5',
'SierpinskiCurveStair,arms=7',
'SierpinskiCurveStair,arms=8',
'HIndexing',
'ImaginaryHalf',
'ImaginaryHalf,radix=3',
'ImaginaryHalf,radix=4',
'ImaginaryHalf,radix=5',
'ImaginaryHalf,radix=37',
'ImaginaryHalf,digit_order=XXY',
'ImaginaryHalf,digit_order=YXX',
'ImaginaryHalf,digit_order=XnXY',
'ImaginaryHalf,digit_order=XnYX',
'ImaginaryHalf,digit_order=YXnX',
'ImaginaryHalf,digit_order=XXY,radix=3',
'Hypot,n_start=37',
'Hypot,points=even,n_start=37',
'Hypot',
'Hypot,points=even',
'Hypot,points=odd',
'HypotOctant',
'HypotOctant,points=even',
'HypotOctant,points=odd',
'TriangularHypot',
'TriangularHypot,n_start=0',
'TriangularHypot,n_start=37',
'TriangularHypot,points=odd',
'TriangularHypot,points=all',
'TriangularHypot,points=hex',
'TriangularHypot,points=hex_rotated',
'TriangularHypot,points=hex_centred',
'DigitGroups',
'DigitGroups,radix=3',
'DigitGroups,radix=4',
'DigitGroups,radix=5',
'DigitGroups,radix=37',
'HilbertCurve',
'SierpinskiArrowheadCentres',
'SierpinskiArrowheadCentres,align=right',
'SierpinskiArrowheadCentres,align=left',
'SierpinskiArrowheadCentres,align=diagonal',
'CubicBase',
'CubicBase,radix=3',
'CubicBase,radix=4',
'CubicBase,radix=37',
'CfracDigits,radix=1',
'CfracDigits',
'CfracDigits,radix=3',
'CfracDigits,radix=4',
'CfracDigits,radix=10',
'CfracDigits,radix=37',
'GcdRationals',
'GcdRationals,pairs_order=rows_reverse',
'GcdRationals,pairs_order=diagonals_down',
'GcdRationals,pairs_order=diagonals_up',
'ZOrderCurve,radix=5',
'ZOrderCurve',
'ZOrderCurve,radix=3',
'ZOrderCurve,radix=9',
'ZOrderCurve,radix=37',
'GosperIslands',
'AR2W2Curve',
'AR2W2Curve,start_shape=D2',
'AR2W2Curve,start_shape=B2',
'AR2W2Curve,start_shape=B1rev',
'AR2W2Curve,start_shape=D1rev',
'AR2W2Curve,start_shape=A2rev',
'BetaOmega',
'KochelCurve',
'CincoCurve',
'WunderlichMeander',
'SacksSpiral',
'TheodorusSpiral',
'ComplexRevolving',
'ComplexPlus',
'ComplexPlus,realpart=2',
'ComplexPlus,realpart=3',
'ComplexPlus,realpart=4',
'ComplexPlus,realpart=5',
'ComplexMinus',
'ComplexMinus,realpart=2',
'ComplexMinus,realpart=3',
'ComplexMinus,realpart=4',
'ComplexMinus,realpart=5',
'LTiling',
'LTiling,L_fill=ends',
'LTiling,L_fill=all',
'FibonacciWordFractal',
'GosperReplicate',
'GosperSide',
'SquareReplicate',
'QuadricCurve',
'QuadricIslands',
'PowerArray',
'PowerArray,radix=3',
'PowerArray,radix=4',
'PixelRings',
'HilbertSpiral',
'CCurve',
'DiamondArms',
'SquareArms',
'HexArms',
'GrayCode',
'GrayCode,radix=3',
'GrayCode,radix=4',
'GrayCode,radix=37',
'GrayCode,apply_type=FsT',
'GrayCode,apply_type=Fs',
'GrayCode,apply_type=Ts',
'GrayCode,apply_type=sF',
'GrayCode,apply_type=sT',
'GrayCode,radix=4,gray_type=modular',
'WunderlichSerpentine',
'WunderlichSerpentine,serpentine_type=100_000_000',
'WunderlichSerpentine,serpentine_type=000_000_001',
'WunderlichSerpentine,radix=2',
'WunderlichSerpentine,radix=4',
'WunderlichSerpentine,radix=5,serpentine_type=coil',
'QuintetCurve',
'QuintetCurve,arms=2',
'QuintetCurve,arms=3',
'QuintetCurve,arms=4',
'QuintetCentres',
'QuintetCentres,arms=2',
'QuintetCentres,arms=3',
'QuintetCentres,arms=4',
'QuintetReplicate',
'DekkingCurve',
'DekkingCentres',
'DiamondSpiral',
'DiamondSpiral,n_start=0',
'DiamondSpiral,n_start=37',
'FractionsTree',
'AlternatePaper,arms=2',
'AlternatePaper',
'AlternatePaper,arms=3',
'AlternatePaper,arms=4',
'AlternatePaper,arms=5',
'AlternatePaper,arms=6',
'AlternatePaper,arms=7',
'AlternatePaper,arms=8',
'SierpinskiArrowhead',
'SierpinskiArrowhead,align=right',
'SierpinskiArrowhead,align=left',
'SierpinskiArrowhead,align=diagonal',
'DiagonalsOctant',
'DiagonalsOctant,direction=up',
'DiagonalsOctant,n_start=0',
'DiagonalsOctant,direction=up,n_start=0',
'DiagonalsOctant,n_start=37',
'DiagonalsOctant,direction=up,n_start=37',
'Corner',
'Corner,wider=1',
'Corner,wider=2',
'Corner,wider=37',
'Corner,n_start=0',
'Corner,wider=1,n_start=0',
'Corner,wider=2,n_start=0',
'Corner,wider=37,n_start=0',
'Corner,n_start=37',
'Corner,wider=1,n_start=37',
'Corner,wider=2,n_start=37',
'Corner,wider=13,n_start=37',
'File',
'SquareSpiral,n_start=0',
'SquareSpiral,n_start=37',
'SquareSpiral,wider=5,n_start=0',
'SquareSpiral,wider=5,n_start=37',
'SquareSpiral,wider=6,n_start=0',
'SquareSpiral,wider=6,n_start=37',
'SquareSpiral',
'SquareSpiral,wider=1',
'SquareSpiral,wider=2',
'SquareSpiral,wider=3',
'SquareSpiral,wider=4',
'SquareSpiral,wider=5',
'SquareSpiral,wider=6',
'SquareSpiral,wider=37',
'ImaginaryBase',
'ImaginaryBase,radix=3',
'ImaginaryBase,radix=4',
'ImaginaryBase,radix=5',
'ImaginaryBase,radix=37',
'GreekKeySpiral',
'GreekKeySpiral,turns=0',
'GreekKeySpiral,turns=1',
'GreekKeySpiral,turns=3',
'GreekKeySpiral,turns=4',
'GreekKeySpiral,turns=5',
'GreekKeySpiral,turns=6',
'GreekKeySpiral,turns=7',
'GreekKeySpiral,turns=8',
'GreekKeySpiral,turns=37',
'AlternatePaperMidpoint',
'AlternatePaperMidpoint,arms=2',
'AlternatePaperMidpoint,arms=3',
'AlternatePaperMidpoint,arms=4',
'AlternatePaperMidpoint,arms=5',
'AlternatePaperMidpoint,arms=6',
'AlternatePaperMidpoint,arms=7',
'AlternatePaperMidpoint,arms=8',
'CretanLabyrinth',
# module list end
# cellular 0 to 255
(map {("CellularRule,rule=$_",
"CellularRule,rule=$_,n_start=0",
"CellularRule,rule=$_,n_start=37")} 0..255),
);
@modules = grep { module_exists($_) } @modules;
sub module_exists {
my ($module) = @_;
if ($module =~ /^\*([^,]+)/) {
require Module::Util;
my $filename = Module::Util::find_installed("Math::PlanePath::$1");
if ($filename) {
return 1;
} else {
MyTestHelpers::diag ("skip optional $module");
return 0;
}
} else {
return 1; # not optional
}
}
foreach (@modules) { s/^\*// }
my @classes = map {(module_parse($_))[0]} @modules;
{ my %seen; @classes = grep {!$seen{$_}++} @classes } # uniq
sub module_parse {
my ($mod) = @_;
my ($class, @parameters) = split /,/, $mod;
return ("Math::PlanePath::$class",
map {/(.*?)=(.*)/ or die; ($1 => $2)} @parameters);
}
sub module_to_pathobj {
my ($mod) = @_;
my ($class, @parameters) = module_parse($mod);
### $mod
### @parameters
eval "require $class" or die;
return $class->new (@parameters);
}
{
eval {
require Module::Util;
my %classes = map {$_=>1} @classes;
foreach my $module (Module::Util::find_in_namespace('Math::PlanePath')) {
next if $classes{$module}; # listed, good
next if $module =~ /^Math::PlanePath::[^:]+::/; # skip Base etc submods
MyTestHelpers::diag ("other module ",$module);
}
};
}
#------------------------------------------------------------------------------
# VERSION
my $want_version = 113;
ok ($Math::PlanePath::VERSION, $want_version, 'VERSION variable');
ok (Math::PlanePath->VERSION, $want_version, 'VERSION class method');
ok (eval { Math::PlanePath->VERSION($want_version); 1 },
1,
"VERSION class check $want_version");
my $check_version = $want_version + 1000;
ok (! eval { Math::PlanePath->VERSION($check_version); 1 },
1,
"VERSION class check $check_version");
#------------------------------------------------------------------------------
# new and VERSION
# foreach my $class (@classes) {
# eval "require $class" or die;
#
# ok (eval { $class->VERSION($want_version); 1 },
# 1,
# "VERSION class check $want_version in $class");
# ok (! eval { $class->VERSION($check_version); 1 },
# 1,
# "VERSION class check $check_version in $class");
#
# my $path = $class->new;
# ok ($path->VERSION, $want_version,
# "VERSION object method in $class");
#
# ok (eval { $path->VERSION($want_version); 1 },
# 1,
# "VERSION object check $want_version in $class");
# ok (! eval { $path->VERSION($check_version); 1 },
# 1,
# "VERSION object check $check_version in $class");
# }
#------------------------------------------------------------------------------
# x_negative, y_negative
foreach my $mod (@modules) {
my $path = module_to_pathobj($mod);
$path->x_negative;
$path->y_negative;
$path->n_start;
# ok (1,1, 'x_negative(),y_negative(),n_start() methods run');
}
#------------------------------------------------------------------------------
# n_to_xy, xy_to_n
my %xy_maximum_duplication =
('Math::PlanePath::DragonCurve' => 2,
'Math::PlanePath::R5DragonCurve' => 2,
'Math::PlanePath::CCurve' => 9999,
'Math::PlanePath::AlternatePaper' => 2,
'Math::PlanePath::TerdragonCurve' => 3,
'Math::PlanePath::KochSnowflakes' => 2,
'Math::PlanePath::QuadricIslands' => 2,
);
my %xy_maximum_duplication_at_origin =
('Math::PlanePath::DragonCurve' => 4,
'Math::PlanePath::TerdragonCurve' => 6,
'Math::PlanePath::R5DragonCurve' => 4,
);
# modules for which rect_to_n_range() is exact
my %rect_exact = (
# rect_to_n_range exact begin
'Math::PlanePath::ImaginaryBase' => 1,
'Math::PlanePath::CincoCurve' => 1,
'Math::PlanePath::DiagonalsAlternating' => 1,
'Math::PlanePath::CornerReplicate' => 1,
'Math::PlanePath::Rows' => 1,
'Math::PlanePath::Columns' => 1,
'Math::PlanePath::Diagonals' => 1,
'Math::PlanePath::DiagonalsOctant' => 1,
'Math::PlanePath::Staircase' => 1,
'Math::PlanePath::StaircaseAlternating' => 1,
'Math::PlanePath::PyramidRows' => 1,
'Math::PlanePath::PyramidSides' => 1,
'Math::PlanePath::CellularRule190' => 1,
'Math::PlanePath::Corner' => 1,
'Math::PlanePath::HilbertCurve' => 1,
'Math::PlanePath::HilbertSpiral' => 1,
'Math::PlanePath::PeanoCurve' => 1,
'Math::PlanePath::ZOrderCurve' => 1,
'Math::PlanePath::Flowsnake' => 1,
'Math::PlanePath::FlowsnakeCentres' => 1,
'Math::PlanePath::QuintetCurve' => 1,
'Math::PlanePath::QuintetCentres' => 1,
'Math::PlanePath::DiamondSpiral' => 1,
'Math::PlanePath::AztecDiamondRings' => 1,
'Math::PlanePath::BetaOmega' => 1,
'Math::PlanePath::AR2W2Curve' => 1,
'Math::PlanePath::KochelCurve' => 1,
'Math::PlanePath::WunderlichMeander' => 1,
'Math::PlanePath::File' => 1,
'Math::PlanePath::KochCurve' => 1,
# rect_to_n_range exact end
);
my %rect_exact_hi = (%rect_exact,
# high is exact but low is not
'Math::PlanePath::SquareSpiral' => 1,
'Math::PlanePath::SquareArms' => 1,
'Math::PlanePath::TriangleSpiralSkewed' => 1,
'Math::PlanePath::MPeaks' => 1,
);
my %rect_before_n_start = ('Math::PlanePath::Rows' => 1,
'Math::PlanePath::Columns' => 1,
);
my %non_linear_frac = (
'Math::PlanePath::SacksSpiral' => 1,
'Math::PlanePath::VogelFloret' => 1,
);
# possible X,Y deltas
my $dxdy_square = {
# "square" steps
'1,0' => 1, # N
'-1,0' => 1, # S
'0,1' => 1, # E
'0,-1' => 1, # W
};
my $dxdy_diagonal = {
# "diagonal" steps
'1,1' => 1, # NE
'1,-1' => 1, # NW
'-1,1' => 1, # SE
'-1,-1' => 1, # SW
};
my $dxdy_one = {
# by one diagonal or square
%$dxdy_square,
%$dxdy_diagonal,
};
my $dxdy_hex = {
# hexagon steps X=+/-2, or diagonally
'2,0' => 1, # Ex2
'-2,0' => 1, # Wx2
%$dxdy_diagonal,
};
my %class_dxdy_allowed
= (
'Math::PlanePath::SquareSpiral' => $dxdy_square,
'Math::PlanePath::GreekKeySpiral' => $dxdy_square,
'Math::PlanePath::PyramidSpiral' => { '-1,1' => 1, # NE
'-1,-1' => 1, # SW
'1,0' => 1, # E
},
'Math::PlanePath::TriangleSpiral' => { '-1,1' => 1, # NE
'-1,-1' => 1, # SW
'2,0' => 1, # Ex2
},
'Math::PlanePath::TriangleSpiralSkewed' => { '-1,1' => 1, # NE
'0,-1' => 1, # S
'1,0' => 1, # E
},
'Math::PlanePath::TriangleSpiralSkewed,skew=right' => { '0,1' => 1, # N
'-1,-1' => 1, # SW
'1,0' => 1, # E
},
'Math::PlanePath::TriangleSpiralSkewed,skew=up' => { '1,1' => 1, # NE
'-1,0' => 1, # W
'0,-1' => 1, # S
},
'Math::PlanePath::TriangleSpiralSkewed,skew=down' => { '1,-1' => 1, # SE
'0,1' => 1, # N
'-1,0' => 1, # W
},
'Math::PlanePath::DiamondSpiral' => { '1,0' => 1, # E at bottom
%$dxdy_diagonal,
},
'Math::PlanePath::PentSpiralSkewed' => {
'-1,1' => 1, # NW
'-1,-1' => 1, # SW
'1,-1' => 1, # SE
'1,0' => 1, # E
'0,1' => 1, # N
},
'Math::PlanePath::HexSpiral' => $dxdy_hex,
'Math::PlanePath::Flowsnake' => $dxdy_hex,
'Math::PlanePath::FlowsnakeCentres' => $dxdy_hex,
'Math::PlanePath::GosperSide' => $dxdy_hex,
# FIXME: 3 directions for arms==1, 6 directions for arms>=2
'Math::PlanePath::TerdragonCurve' => $dxdy_hex,
'Math::PlanePath::TerdragonMidpoint' => $dxdy_hex,
'Math::PlanePath::KochCurve' => $dxdy_hex,
# except for jumps at ends/rings
# 'Math::PlanePath::KochPeaks' => $dxdy_hex,
# 'Math::PlanePath::KochSnowflakes' => $dxdy_hex,
# 'Math::PlanePath::GosperIslands' => $dxdy_hex,
'Math::PlanePath::QuintetCurve' => $dxdy_square,
'Math::PlanePath::QuintetCentres' => $dxdy_one,
# Math::PlanePath::QuintetReplicate -- mucho distance
# 'Math::PlanePath::SierpinskiCurve' => $dxdy_one, # only spacing==1
'Math::PlanePath::HIndexing' => $dxdy_square,
'Math::PlanePath::HexSpiralSkewed' => {
'-1,1' => 1, # NW
'1,-1' => 1, # SE
%$dxdy_square,
},
'Math::PlanePath::HeptSpiralSkewed' => {
'-1,1' => 1, # NW
%$dxdy_square,
},
'Math::PlanePath::OctagramSpiral' => $dxdy_one,
'Math::PlanePath::KnightSpiral' => { '1,2' => 1,
'-1,2' => 1,
'1,-2' => 1,
'-1,-2' => 1,
'2,1' => 1,
'-2,1' => 1,
'2,-1' => 1,
'-2,-1' => 1,
},
'Math::PlanePath::PixelRings' => {
%$dxdy_one,
'2,1' => 1, # from N=5 to N=6
},
'Math::PlanePath::HilbertCurve' => $dxdy_square,
'Math::PlanePath::HilbertSpiral' => $dxdy_square,
'Math::PlanePath::PeanoCurve' => $dxdy_square,
'Math::PlanePath::WunderlichSerpentine' => $dxdy_square,
'Math::PlanePath::BetaOmega' => $dxdy_square,
'Math::PlanePath::AR2W2Curve' => $dxdy_one,
'Math::PlanePath::DragonCurve' => $dxdy_square,
'Math::PlanePath::DragonMidpoint' => $dxdy_square,
'Math::PlanePath::DragonRounded' => $dxdy_one,
'Math::PlanePath::R5DragonCurve' => $dxdy_square,
'Math::PlanePath::R5DragonMidpoint' => $dxdy_square,
'Math::PlanePath::CCurve' => $dxdy_square,
'Math::PlanePath::HilbertMidpoint' => { %$dxdy_diagonal,
'2,0' => 1,
'0,2' => 1,
'-2,0' => 1,
'0,-2' => 1,
},
);
#------------------------------------------------------------------------------
my ($pos_infinity, $neg_infinity, $nan);
my ($is_infinity, $is_nan);
if (! eval { require Data::Float; 1 }) {
MyTestHelpers::diag ("Data::Float not available");
} elsif (! Data::Float::have_infinite()) {
MyTestHelpers::diag ("Data::Float have_infinite() is false");
} else {
$is_infinity = sub {
my ($x) = @_;
return defined($x) && Data::Float::float_is_infinite($x);
};
$is_nan = sub {
my ($x) = @_;
return defined($x) && Data::Float::float_is_nan($x);
};
$pos_infinity = Data::Float::pos_infinity();
$neg_infinity = Data::Float::neg_infinity();
$nan = Data::Float::nan();
}
sub pos_infinity_maybe {
return (defined $pos_infinity ? $pos_infinity : ());
}
sub neg_infinity_maybe {
return (defined $neg_infinity ? $neg_infinity : ());
}
sub dbl_max {
require POSIX;
return POSIX::DBL_MAX();
}
sub dbl_max_neg {
require POSIX;
return - POSIX::DBL_MAX();
}
sub dbl_max_for_class_xy {
my ($path) = @_;
### dbl_max_for_class_xy(): "$path"
if ($path->isa('Math::PlanePath::CoprimeColumns')
|| $path->isa('Math::PlanePath::DiagonalRationals')
|| $path->isa('Math::PlanePath::DivisibleColumns')
|| $path->isa('Math::PlanePath::CellularRule')
|| $path->isa('Math::PlanePath::DragonCurve')
|| $path->isa('Math::PlanePath::PixelRings')
) {
### don't try DBL_MAX on this path xy_to_n() ...
return ();
}
return dbl_max();
}
sub dbl_max_neg_for_class_xy {
my ($path) = @_;
if (dbl_max_for_class_xy($path)) {
return dbl_max_neg();
} else {
return ();
}
}
sub dbl_max_for_class_rect {
my ($path) = @_;
# no DBL_MAX on these
if ($path->isa('Math::PlanePath::CoprimeColumns')
|| $path->isa('Math::PlanePath::DiagonalRationals')
|| $path->isa('Math::PlanePath::DivisibleColumns')
|| $path->isa('Math::PlanePath::CellularRule')
|| $path->isa('Math::PlanePath::PixelRings')
) {
### don't try DBL_MAX on this path rect_to_n_range() ...
return ();
}
return dbl_max();
}
sub dbl_max_neg_for_class_rect {
my ($path) = @_;
if (dbl_max_for_class_rect($path)) {
return dbl_max_neg();
} else {
return ();
}
}
sub is_pos_infinity {
my ($n) = @_;
return defined $n && defined $pos_infinity && $n == $pos_infinity;
}
sub is_neg_infinity {
my ($n) = @_;
return defined $n && defined $neg_infinity && $n == $neg_infinity;
}
sub pythagorean_diag {
my ($path,$x,$y) = @_;
$path->isa('Math::PlanePath::PythagoreanTree')
or return;
my $z = Math::Libm::hypot ($x, $y);
my $z_not_int = (int($z) != $z);
my $z_even = ! ($z & 1);
MyTestHelpers::diag ("x=$x y=$y, hypot z=$z z_not_int='$z_not_int' z_even='$z_even'");
my $psq = ($z+$x)/2;
my $p = sqrt(($z+$x)/2);
my $p_not_int = ($p != int($p));
MyTestHelpers::diag ("psq=$psq p=$p p_not_int='$p_not_int'");
my $qsq = ($z-$x)/2;
my $q = sqrt(($z-$x)/2);
my $q_not_int = ($q != int($q));
MyTestHelpers::diag ("qsq=$qsq q=$q q_not_int='$q_not_int'");
}
{
my $default_limit = ($ENV{'MATH_PLANEPATH_TEST_LIMIT'} || 30);
my $rect_limit = $ENV{'MATH_PLANEPATH_TEST_RECT_LIMIT'} || 4;
MyTestHelpers::diag ("test limit $default_limit, rect limit $rect_limit");
my $good = 1;
foreach my $mod (@modules) {
if ($verbose) {
MyTestHelpers::diag ($mod);
}
my ($class, %parameters) = module_parse($mod);
### $class
eval "require $class" or die;
my $xy_maximum_duplication = $xy_maximum_duplication{$class} || 0;
my $dxdy_allowed
= $class_dxdy_allowed{$class.",skew=".($parameters{'skew'}||'')}
|| $class_dxdy_allowed{$class};
if ($mod =~ /^PeanoCurve|^WunderlichSerpentine/
&& $parameters{'radix'}
&& ($parameters{'radix'} % 2) == 0) {
undef $dxdy_allowed; # even radix doesn't join up
}
if ($parameters{'arms'} && $parameters{'arms'} > 1) {
# ENHANCE-ME: watch for dxdy within each arm
undef $dxdy_allowed;
}
#
# MyTestHelpers::diag ($mod);
#
my $depth_limit = 10;
my $limit = $default_limit;
if (defined (my $step = $parameters{'step'})) {
if ($limit < 6*$step) {
$limit = 6*$step; # so goes into x/y negative
}
}
if ($mod =~ /^ArchimedeanChords/) {
if ($limit > 1100) {
$limit = 1100; # bit slow otherwise
}
}
if ($mod =~ /^CoprimeColumns|^DiagonalRationals/) {
if ($limit > 1100) {
$limit = 1100; # bit slow otherwise
}
}
my $report = sub {
my $name = $mod;
MyTestHelpers::diag ($name, ' oops ', @_);
$good = 0;
# exit 1;
};
my $path = $class->new (width => 20,
height => 20,
%parameters);
my $got_arms = $path->arms_count;
foreach my $pinfo ($path->parameter_info_list) {
if ($pinfo->{'type'} eq 'enum') {
my $choices = $pinfo->{'choices'};
my $num_choices = scalar(@$choices);
if (my $choices_display = $pinfo->{'choices_display'}) {
my $num_choices_display = scalar(@$choices_display);
if ($num_choices != $num_choices_display) {
&$report("parameter info $pinfo->{'name'} choices $num_choices but choices_display $num_choices_display");
}
}
}
}
if ($parameters{'arms'} && $got_arms != $parameters{'arms'}) {
&$report("arms_count()==$got_arms expect $parameters{'arms'}");
}
unless ($got_arms >= 1) {
&$report("arms_count()==$got_arms should be >=1");
}
my $arms_count = $path->arms_count;
my $n_start = $path->n_start;
my $n_frac_discontinuity = $path->n_frac_discontinuity;
{
my ($x,$y) = $path->n_to_xy($n_start);
if (! defined $x) {
unless ($path->isa('Math::PlanePath::File')) {
&$report("n_start()==$n_start doesn't have an n_to_xy()");
}
} else {
my ($n_lo, $n_hi) = $path->rect_to_n_range ($x,$y, $x,$y);
if ($n_lo > $n_start || $n_hi < $n_start) {
&$report("n_start()==$n_start outside rect_to_n_range() $n_lo..$n_hi");
}
}
}
if (# VogelFloret has a secret undocumented return for N=0
! $path->isa('Math::PlanePath::VogelFloret')
# Rows/Columns secret undocumented extend into negatives ...
&& ! $path->isa('Math::PlanePath::Rows')
&& ! $path->isa('Math::PlanePath::Columns')) {
my $n = $n_start - 1;
{
my @xy = $path->n_to_xy($n);
if (scalar @xy) {
&$report("n_to_xy() at n_start()-1=$n has X,Y but should not");
}
}
foreach my $method ('n_to_rsquared', 'n_to_radius') {
my @ret = $path->$method($n);
if (scalar(@ret) != 1) {
&$report("$method() at n_start()-1 return not one value");
} elsif (defined $ret[0]) {
&$report("$method() at n_start()-1 has defined value but should not");
}
foreach my $offset (1, 2, 123) {
### n_to_r (n_start - offset): $offset
my $n = $n_start - $offset;
my @ret = $path->$method($n);
if ($path->isa('Math::PlanePath::File')) {
@ret = (undef); # all undefs for File
}
my $num_values = scalar(@ret);
$num_values == 1
or &$report("$method(n_start - $offset) got $num_values values, want 1");
if ($path->isa('Math::PlanePath::Rows')
|| $path->isa('Math::PlanePath::Columns')) {
### Rows,Columns has secret values for negative N, pretend not ...
@ret = (undef);
}
if ($offset == 1 && $path->isa('Math::PlanePath::VogelFloret')) {
### VogelFloret has a secret undocumented return for N=0 ...
@ret = (undef);
}
my ($ret) = @ret;
if (defined $ret) {
&$report("$method($n) n_start-$offset is ",$ret," expected undef");
}
}
}
}
{
my $saw_warning;
local $SIG{'__WARN__'} = sub { $saw_warning = 1; };
foreach my $method ('n_to_xy','n_to_dxdy',
'n_to_rsquared',
'n_to_radius',
($path->tree_n_num_children($n_start)
? ('tree_n_to_depth',
'tree_depth_to_n',
'tree_depth_to_n_end',
'tree_depth_to_n_range',
'tree_n_parent',
'tree_n_root',
'tree_n_children',
'tree_n_num_children',
)
: ())){
$saw_warning = 0;
$path->$method(undef);
$saw_warning or &$report("$method(undef) doesn't give a warning");
}
{
$saw_warning = 0;
$path->xy_to_n(0,undef);
$saw_warning or &$report("xy_to_n(0,undef) doesn't give a warning");
}
{
$saw_warning = 0;
$path->xy_to_n(undef,0);
$saw_warning or &$report("xy_to_n(undef,0) doesn't give a warning");
}
# No warning if xy_is_visited() is a constant, skip test in that case.
unless (coderef_is_const($path->can('xy_is_visited'))) {
$saw_warning = 0;
$path->xy_is_visited(0,undef);
$saw_warning or &$report("xy_is_visited(0,undef) doesn't give a warning");
$saw_warning = 0;
$path->xy_is_visited(undef,0);
$saw_warning or &$report("xy_is_visited(undef,0) doesn't give a warning");
}
}
# undef ok if nothing sensible
# +/-inf ok
# nan not intended, but might be ok
# finite could be a fixed x==0
if (defined $pos_infinity) {
{
### n_to_xy($pos_infinity) ...
my ($x, $y) = $path->n_to_xy($pos_infinity);
if ($path->isa('Math::PlanePath::File')) {
# all undefs for File
if (! defined $x) { $x = $pos_infinity }
if (! defined $y) { $y = $pos_infinity }
} elsif ($path->isa('Math::PlanePath::PyramidRows')
&& ! $parameters{'step'}) {
# x==0 normal from step==0, fake it up to pass test
if (defined $x && $x == 0) { $x = $pos_infinity }
}
(is_pos_infinity($x) || is_neg_infinity($x) || &$is_nan($x))
or &$report("n_to_xy($pos_infinity) x is $x");
(is_pos_infinity($y) || is_neg_infinity($y) || &$is_nan($y))
or &$report("n_to_xy($pos_infinity) y is $y");
}
{
### n_to_dxdy($pos_infinity) ...
my @dxdy = $path->n_to_xy($pos_infinity);
if ($path->isa('Math::PlanePath::File')) {
# all undefs for File
@dxdy = ($pos_infinity, $pos_infinity);
}
my $num_values = scalar(@dxdy);
$num_values == 2
or &$report("n_to_dxdy(pos_infinity) got $num_values values, want 2");
my ($dx,$dy) = @dxdy;
(is_pos_infinity($dx) || is_neg_infinity($dx) || &$is_nan($dx))
or &$report("n_to_dxdy($pos_infinity) dx is $dx");
(is_pos_infinity($dy) || is_neg_infinity($dy) || &$is_nan($dy))
or &$report("n_to_dxdy($pos_infinity) dy is $dy");
}
foreach my $method ('n_to_rsquared','n_to_radius') {
### n_to_r pos_infinity ...
my @ret = $path->$method($pos_infinity);
if ($path->isa('Math::PlanePath::File')) {
# all undefs for File
@ret = ($pos_infinity);
}
my $num_values = scalar(@ret);
$num_values == 1
or &$report("$method(pos_infinity) got $num_values values, want 1");
my ($ret) = @ret;
# allow NaN too, since sqrt(+inf) in various classes gives nan
(is_pos_infinity($ret) || &$is_nan($ret))
or &$report("$method($pos_infinity) ",$ret," expected +infinity");
}
{
### tree_n_children($pos_infinity) ...
my @children = $path->tree_n_children($pos_infinity);
}
{
### tree_n_num_children($pos_infinity) ...
my $num_children = $path->tree_n_num_children($pos_infinity);
}
{
### tree_n_to_subheight($pos_infinity) ...
my $height = $path->tree_n_to_subheight($pos_infinity);
if ($path->tree_n_num_children($n_start)) {
unless (! defined $height || is_pos_infinity($height)) {
&$report("tree_n_to_subheight($pos_infinity) ",$height," expected +inf");
}
} else {
unless (equal(0,$height)) {
&$report("tree_n_to_subheight($pos_infinity) ",$height," expected 0");
}
}
}
# {
# ### _EXPERIMENTAL__tree_n_to_leafdist($pos_infinity) ...
# my $leafdist = $path->_EXPERIMENTAL__tree_n_to_leafdist($pos_infinity);
# # if ($path->tree_n_num_children($n_start)) {
# # unless (! defined $leafdist || is_pos_infinity($leafdist)) {
# # &$report("_EXPERIMENTAL__tree_n_to_leafdist($pos_infinity) ",$leafdist," expected +inf");
# # }
# # } else {
# # unless (equal(0,$leafdist)) {
# # &$report("_EXPERIMENTAL__tree_n_to_leafdist($pos_infinity) ",$leafdist," expected 0");
# # }
# # }
# }
}
if (defined $neg_infinity) {
{
### n_to_xy($neg_infinity) ...
my @xy = $path->n_to_xy($neg_infinity);
if ($path->isa('Math::PlanePath::Rows')) {
# secret negative n for Rows
my ($x, $y) = @xy;
($x==$pos_infinity || $x==$neg_infinity || &$is_nan($x))
or &$report("n_to_xy($neg_infinity) x is $x");
($y==$neg_infinity)
or &$report("n_to_xy($neg_infinity) y is $y");
} elsif ($path->isa('Math::PlanePath::Columns')) {
# secret negative n for Columns
my ($x, $y) = @xy;
($x==$neg_infinity)
or &$report("n_to_xy($neg_infinity) x is $x");
($y==$pos_infinity || $y==$neg_infinity || &$is_nan($y))
or &$report("n_to_xy($neg_infinity) y is $y");
} else {
scalar(@xy) == 0
or &$report("n_to_xy($neg_infinity) xy is ",join(',',@xy));
}
}
{
### n_to_dxdy($neg_infinity) ...
my @dxdy = $path->n_to_xy($neg_infinity);
my $num_values = scalar(@dxdy);
if (($path->isa('Math::PlanePath::Rows')
|| $path->isa('Math::PlanePath::Columns'))
&& $num_values == 2) {
# Rows,Columns has secret values for negative N, pretend not
$num_values = 0;
}
$num_values == 0
or &$report("n_to_dxdy(neg_infinity) got $num_values values, want 0");
}
foreach my $method ('n_to_rsquared','n_to_radius') {
### n_to_r (neg_infinity) ...
my @ret = $path->$method($neg_infinity);
if ($path->isa('Math::PlanePath::File')) {
@ret = (undef); # all undefs for File
}
my $num_values = scalar(@ret);
$num_values == 1
or &$report("$method($neg_infinity) got $num_values values, want 1");
if ($path->isa('Math::PlanePath::Rows')
|| $path->isa('Math::PlanePath::Columns')) {
### Rows,Columns has secret values for negative N, pretend not ...
@ret = (undef);
}
my ($ret) = @ret;
if (defined $ret) {
&$report("$method($neg_infinity) $ret expected undef");
}
}
{
### tree_n_children($neg_infinity) ...
my @children = $path->tree_n_children($neg_infinity);
if (@children) {
&$report("tree_n_children($neg_infinity) ",@children," expected none");
}
}
{
### tree_n_num_children($neg_infinity) ...
my $num_children = $path->tree_n_num_children($neg_infinity);
if (defined $num_children) {
&$report("tree_n_children($neg_infinity) ",$num_children," expected undef");
}
}
{
### tree_n_to_subheight($neg_infinity) ...
my $height = $path->tree_n_to_subheight($neg_infinity);
if ($path->tree_n_num_children($n_start)) {
if (defined $height) {
&$report("tree_n_to_subheight($neg_infinity) ",$height," expected undef");
}
}
}
if ($path->can('_EXPERIMENTAL__tree_n_to_leafdist')) {
my $leafdist = $path->_EXPERIMENTAL__tree_n_to_leafdist($neg_infinity);
if ($path->tree_n_num_children($n_start)) {
if (defined $leafdist) {
&$report("_EXPERIMENTAL__tree_n_to_leafdist($neg_infinity) ",$leafdist," expected undef");
}
}
}
}
# nan input documented loosely as yet ...
if (defined $nan) {
{
my @xy = $path->n_to_xy($nan);
if ($path->isa('Math::PlanePath::File')) {
# allow empty from File without filename
if (! @xy) { @xy = ($nan, $nan); }
} elsif ($path->isa('Math::PlanePath::PyramidRows')
&& ! $parameters{'step'}) {
# x==0 normal from step==0, fake it up to pass test
if (defined $xy[0] && $xy[0] == 0) { $xy[0] = $nan }
}
my ($x, $y) = @xy;
&$is_nan($x) or &$report("n_to_xy($nan) x not nan, got ", $x);
&$is_nan($y) or &$report("n_to_xy($nan) y not nan, got ", $y);
}
{
my @dxdy = $path->n_to_xy($nan);
if ($path->isa('Math::PlanePath::File')
&& @dxdy == 0) {
# allow empty from File without filename
@dxdy = ($nan, $nan);
}
my $num_values = scalar(@dxdy);
$num_values == 2
or &$report("n_to_dxdy(nan) got $num_values values, want 2");
my ($dx,$dy) = @dxdy;
&$is_nan($dx) or &$report("n_to_dxdy($nan) dx not nan, got ", $dx);
&$is_nan($dy) or &$report("n_to_dxdy($nan) dy not nan, got ", $dy);
}
{
### tree_n_children($nan) ...
my @children = $path->tree_n_children($nan);
# ENHANCE-ME: what should nan return?
# if (@children) {
# &$report("tree_n_children($nan) ",@children," expected none");
# }
}
{
### tree_n_num_children($nan) ...
my $num_children = $path->tree_n_num_children($nan);
# ENHANCE-ME: what should nan return?
# &$is_nan($num_children)
# or &$report("tree_n_children($nan) ",$num_children," expected nan");
}
{
### tree_n_to_subheight($nan) ...
my $height = $path->tree_n_to_subheight($nan);
if ($path->tree_n_num_children($n_start)) {
(! defined $height || &$is_nan($height))
or &$report("tree_n_to_subheight($nan) ",$height," expected nan");
}
}
# {
# ### _EXPERIMENTAL__tree_n_to_leafdist($nan) ...
# my $leafdist = $path->_EXPERIMENTAL__tree_n_to_leafdist($nan);
# if ($path->tree_n_num_children($n_start)) {
# (! defined $leafdist || &$is_nan($leafdist))
# or &$report("_EXPERIMENTAL__tree_n_to_leafdist($nan) ",$leafdist," expected nan");
# }
# }
}
foreach my $x
(0,
pos_infinity_maybe(),
neg_infinity_maybe(),
dbl_max_for_class_xy($path),
dbl_max_neg_for_class_xy($path)) {
foreach my $y (0,
pos_infinity_maybe(),
neg_infinity_maybe(),,
dbl_max_for_class_xy($path),
dbl_max_neg_for_class_xy($path)) {
next if ! defined $y;
### xy_to_n: $x, $y
my @n = $path->xy_to_n($x,$y);
scalar(@n) == 1
or &$report("xy_to_n($x,$y) want 1 value, got ",scalar(@n));
# my $n = $n[0];
# &$is_infinity($n) or &$report("xy_to_n($x,$y) n not inf, got ",$n);
}
}
foreach my $x1 (0,
pos_infinity_maybe(),
neg_infinity_maybe(),
dbl_max_for_class_rect($path),
dbl_max_neg_for_class_rect($path)) {
foreach my $x2 (0,
pos_infinity_maybe(),
neg_infinity_maybe(),
dbl_max_for_class_rect($path),
dbl_max_neg_for_class_rect($path)) {
foreach my $y1 (0,
pos_infinity_maybe(),
neg_infinity_maybe(),
dbl_max_for_class_rect($path),
dbl_max_neg_for_class_rect($path)) {
foreach my $y2 (0,
pos_infinity_maybe(),
neg_infinity_maybe(),
dbl_max_for_class_rect($path),
dbl_max_neg_for_class_rect($path)) {
my @nn = $path->rect_to_n_range($x1,$y1, $x2,$y2);
scalar(@nn) == 2
or &$report("rect_to_n_range($x1,$y1, $x2,$y2) want 2 values, got ",scalar(@nn));
# &$is_infinity($n) or &$report("xy_to_n($x,$y) n not inf, got ",$n);
}
}
}
}
my $x_minimum = $path->x_minimum;
my $x_maximum = $path->x_maximum;
my $y_minimum = $path->y_minimum;
my $y_maximum = $path->y_maximum;
my $sumxy_minimum = $path->sumxy_minimum;
my $sumxy_maximum = $path->sumxy_maximum;
my $sumabsxy_minimum = $path->sumabsxy_minimum;
my $sumabsxy_maximum = $path->sumabsxy_maximum;
my $diffxy_minimum = $path->diffxy_minimum;
my $diffxy_maximum = $path->diffxy_maximum;
my $absdiffxy_minimum = $path->absdiffxy_minimum;
my $absdiffxy_maximum = $path->absdiffxy_maximum;
my $gcdxy_minimum = $path->gcdxy_minimum;
my $gcdxy_maximum = $path->gcdxy_maximum;
my %saw_n_to_xy;
my %count_n_to_xy;
my $got_x_negative = 0;
my $got_y_negative = 0;
my $got_x_minimum;
my $got_y_minimum;
my ($prev_x, $prev_y);
my @n_to_x;
my @n_to_y;
foreach my $n ($n_start .. $n_start + $limit) {
my ($x, $y) = $path->n_to_xy ($n)
or next;
$n_to_x[$n] = $x;
$n_to_y[$n] = $y;
defined $x or &$report("n_to_xy($n) X undef");
defined $y or &$report("n_to_xy($n) Y undef");
if ($x < 0) { $got_x_negative = 1; }
if ($y < 0) { $got_y_negative = 1; }
if (defined $x_minimum && $x < $x_minimum) {
&$report("n_to_xy($n) X=$x below x_minimum=$x_minimum");
}
if (defined $x_maximum && $x > $x_maximum) {
&$report("n_to_xy($n) X=$x below x_maximum=$x_maximum");
}
if (defined $y_minimum && $y < $y_minimum) {
&$report("n_to_xy($n) Y=$y below y_minimum=$y_minimum");
}
if (defined $y_maximum && $y > $y_maximum) {
&$report("n_to_xy($n) Y=$y below y_maximum=$y_maximum");
}
# if (! defined $got_x_minimum || $x < $got_x_minimum) {
# $got_x_minimum = $x;
# }
# if (! defined $got_y_minimum || $y < $got_y_minimum) {
# $got_y_minimum = $y;
# }
# if (! defined $got_x_maximum || $x < $got_x_maximum) {
# $got_x_maximum = $x;
# }
# if (! defined $got_y_maximum || $y < $got_y_maximum) {
# $got_y_maximum = $y;
# }
{
my $sumxy = $x + $y;
if (defined $sumxy_minimum && $sumxy < $sumxy_minimum) {
&$report("n_to_xy($n) X+Y=$sumxy below sumxy_minimum=$sumxy_minimum");
}
if (defined $sumxy_maximum && $sumxy > $sumxy_maximum) {
&$report("n_to_xy($n) X+Y=$sumxy above sumxy_maximum=$sumxy_maximum");
}
}
{
my $sumabsxy = abs($x) + abs($y);
if (defined $sumabsxy_minimum && $sumabsxy < $sumabsxy_minimum) {
&$report("n_to_xy($n) abs(X)+abs(Y)=$sumabsxy below sumabsxy_minimum=$sumabsxy_minimum");
}
if (defined $sumabsxy_maximum && $sumabsxy > $sumabsxy_maximum) {
&$report("n_to_xy($n) abs(X)+abs(Y)=$sumabsxy above sumabsxy_maximum=$sumabsxy_maximum");
}
}
{
my $diffxy = $x - $y;
if (defined $diffxy_minimum && $diffxy < $diffxy_minimum) {
&$report("n_to_xy($n) X-Y=$diffxy below diffxy_minimum=$diffxy_minimum");
}
if (defined $diffxy_maximum && $diffxy > $diffxy_maximum) {
&$report("n_to_xy($n) X-Y=$diffxy above diffxy_maximum=$diffxy_maximum");
}
}
{
my $absdiffxy = abs($x - $y);
if (defined $absdiffxy_minimum && $absdiffxy < $absdiffxy_minimum) {
&$report("n_to_xy($n) abs(X-Y)=$absdiffxy below absdiffxy_minimum=$absdiffxy_minimum");
}
if (defined $absdiffxy_maximum && $absdiffxy > $absdiffxy_maximum) {
&$report("n_to_xy($n) abs(X-Y)=$absdiffxy above absdiffxy_maximum=$absdiffxy_maximum");
}
}
{
my $gcdxy = gcd(abs($x),abs($y));
if (defined $gcdxy_minimum && $gcdxy < $gcdxy_minimum) {
&$report("n_to_xy($n) gcd($x,$y)=$gcdxy below gcdxy_minimum=$gcdxy_minimum");
}
if (defined $gcdxy_maximum && $gcdxy > $gcdxy_maximum) {
&$report("n_to_xy($n) gcd($x,$y)=$gcdxy above gcdxy_maximum=$gcdxy_maximum");
}
}
my $xystr = (int($x) == $x && int($y) == $y
? sprintf('%d,%d', $x,$y)
: sprintf('%.3f,%.3f', $x,$y));
if ($count_n_to_xy{$xystr}++ > $xy_maximum_duplication) {
unless ($x == 0 && $y == 0
&& $count_n_to_xy{$xystr} <= $xy_maximum_duplication_at_origin{$class}) {
&$report ("n_to_xy($n) duplicate$count_n_to_xy{$xystr} xy=$xystr prev n=$saw_n_to_xy{$xystr}");
}
}
$saw_n_to_xy{$xystr} = $n;
my ($dx,$dy);
if (defined $prev_x) { $dx = $x - $prev_x; }
if (defined $prev_y) { $dy = $y - $prev_y; }
if ($dxdy_allowed) {
if (defined $prev_x) {
my $dxdy = "$dx,$dy";
$dxdy_allowed->{$dxdy}
or &$report ("n=$n dxdy=$dxdy not allowed");
}
($prev_x, $prev_y) = ($x, $y);
}
{
my ($n_lo, $n_hi) = $path->rect_to_n_range
(0,0,
$x + ($x >= 0 ? .4 : -.4),
$y + ($y >= 0 ? .4 : -.4));
$n_lo <= $n
or &$report ("rect_to_n_range() lo n=$n xy=$xystr, got $n_lo");
$n_hi >= $n
or &$report ("rect_to_n_range() hi n=$n xy=$xystr, got $n_hi");
$n_lo == int($n_lo)
or &$report ("rect_to_n_range() lo n=$n xy=$xystr, got $n_lo, integer");
$n_hi == int($n_hi)
or &$report ("rect_to_n_range() hi n=$n xy=$xystr, got $n_hi, integer");
$n_lo >= $n_start
or &$report ("rect_to_n_range(0,0,$x,$y)+.4 n_lo=$n_lo is before n_start=$n_start");
}
{
my ($n_lo, $n_hi) = $path->rect_to_n_range ($x,$y, $x,$y);
($rect_exact{$class} ? $n_lo == $n : $n_lo <= $n)
or &$report ("rect_to_n_range() lo n=$n xy=$xystr, got $n_lo");
($rect_exact_hi{$class} ? $n_hi == $n : $n_hi >= $n)
or &$report ("rect_to_n_range() hi n=$n xy=$xystr, got $n_hi");
$n_lo == int($n_lo)
or &$report ("rect_to_n_range() lo n=$n xy=$xystr, got n_lo=$n_lo, should be an integer");
$n_hi == int($n_hi)
or &$report ("rect_to_n_range() hi n=$n xy=$xystr, got n_hi=$n_hi, should be an integer");
$n_lo >= $n_start
or &$report ("rect_to_n_range() n_lo=$n_lo is before n_start=$n_start");
}
unless ($xy_maximum_duplication > 0) {
foreach my $x_offset (0) { # bit slow: , -0.2, 0.2) {
foreach my $y_offset (0, +0.2) { # bit slow: , -0.2) {
my $rev_n = $path->xy_to_n ($x + $x_offset, $y + $y_offset);
### try xy_to_n from: "n=$n xy=$x,$y xy=$xystr x_offset=$x_offset y_offset=$y_offset"
### $rev_n
unless (defined $rev_n && $n == $rev_n) {
&$report ("xy_to_n() rev n=$n xy=$xystr x_offset=$x_offset y_offset=$y_offset got ".(defined $rev_n ? $rev_n : 'undef'));
pythagorean_diag($path,$x,$y);
}
}
}
}
}
#--------------------------------------------------------------------------
### n_to_xy() fractional ...
unless ($non_linear_frac{$class}
|| defined $n_frac_discontinuity) {
foreach my $n ($n_start .. $#n_to_x - $arms_count) {
my $x = $n_to_x[$n];
my $y = $n_to_y[$n];
my $next_x = $n_to_x[$n+$arms_count];
my $next_y = $n_to_y[$n+$arms_count];
next unless defined $x && defined $next_x;
my $dx = $next_x - $x;
my $dy = $next_y - $y;
foreach my $frac (0.25, 0.75) {
my $n_frac = $n + $frac;
my ($got_x,$got_y) = $path->n_to_xy($n_frac);
my $want_x = $x + $frac*$dx;
my $want_y = $y + $frac*$dy;
abs($want_x - $got_x) < 0.00001
or &$report ("n_to_xy($n_frac) got_x=$got_x want_x=$want_x");
abs($want_y - $got_y) < 0.00001
or &$report ("n_to_xy($n_frac) got_y=$got_y want_y=$want_y");
}
}
}
#--------------------------------------------------------------------------
### n_to_dxdy() ...
if ($path->can('n_to_dxdy') != Math::PlanePath->can('n_to_dxdy')) {
MyTestHelpers::diag ($mod, ' n_to_dxdy()');
foreach my $n ($n_start .. $#n_to_x - $arms_count) {
my $x = $n_to_x[$n];
my $y = $n_to_y[$n];
my $next_x = $n_to_x[$n+$arms_count];
my $next_y = $n_to_y[$n+$arms_count];
next unless defined $x && defined $next_x;
my $want_dx = $next_x - $x;
my $want_dy = $next_y - $y;
my ($got_dx,$got_dy) = $path->n_to_dxdy($n);
$want_dx == $got_dx
or &$report ("n_to_dxdy($n) got_dx=$got_dx want_dx=$want_dx (next_x=$n_to_x[$n+$arms_count], x=$n_to_x[$n])");
$want_dy == $got_dy
or &$report ("n_to_dxdy($n) got_dy=$got_dy want_dy=$want_dy");
}
foreach my $n ($n_start .. $n_start + $limit) {
foreach my $offset (0.25, 0.75) {
my $n = $n + $offset;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+$arms_count);
my $want_dx = ($next_x - $x);
my $want_dy = ($next_y - $y);
my ($got_dx,$got_dy) = $path->n_to_dxdy($n);
$want_dx == $got_dx
or &$report ("n_to_dxdy($n) got_dx=$got_dx want_dx=$want_dx");
$want_dy == $got_dy
or &$report ("n_to_dxdy($n) got_dy=$got_dy want_dy=$want_dy");
}
}
}
#--------------------------------------------------------------------------
### n_to_rsquared() vs X^2,Y^2 ...
if ($path->can('n_to_rsquared') != Math::PlanePath->can('n_to_rsquared')) {
foreach my $n ($n_start .. $#n_to_x) {
my $x = $n_to_x[$n];
my $y = $n_to_y[$n];
my ($n_to_rsquared) = $path->n_to_rsquared($n);
my $xy_to_rsquared = $x*$x + $y*$y;
if (abs($n_to_rsquared - $xy_to_rsquared) > 0.0000001) {
&$report ("n_to_rsquared() at n=$n,x=$x,y=$y got $n_to_rsquared whereas x^2+y^2=$xy_to_rsquared");
}
}
}
#--------------------------------------------------------------------------
### n_to_radius() vs X^2,Y^2 ...
if ($path->can('n_to_radius') != Math::PlanePath->can('n_to_radius')) {
foreach my $n ($n_start .. $#n_to_x) {
my $x = $n_to_x[$n];
my $y = $n_to_y[$n];
my ($n_to_radius) = $path->n_to_radius($n);
my $xy_to_radius = sqrt($x*$x + $y*$y);
if (abs($n_to_radius - $xy_to_radius) > 0.0000001) {
&$report ("n_to_radius() at n=$n,x=$x,y=$y got $n_to_radius whereas x^2+y^2=$xy_to_radius");
}
}
}
#--------------------------------------------------------------------------
### n_to_xy() various bogus values return 0 or 2 values and not crash ...
foreach my $n (-100, -2, -1, -0.6, -0.5, -0.4,
0, 0.4, 0.5, 0.6) {
my @xy = $path->n_to_xy ($n);
(@xy == 0 || @xy == 2)
or &$report ("n_to_xy() n=$n got ",scalar(@xy)," values");
}
foreach my $elem ([-1,-1, -1,-1],
) {
my ($x1,$y1,$x2,$y2) = @$elem;
my ($got_lo, $got_hi) = $path->rect_to_n_range ($x1,$y1, $x2,$y2);
(defined $got_lo && defined $got_hi)
or &$report ("rect_to_n_range() x1=$x1,y1=$y1, x2=$x2,y2=$y2 undefs");
if ($got_hi >= $got_lo) {
$got_lo >= $n_start
or &$report ("rect_to_n_range() got_lo=$got_lo is before n_start=$n_start");
}
}
#--------------------------------------------------------------------------
### x negative xy_to_n() ...
foreach my $x (-100, -99) {
### $x
my @n = $path->xy_to_n ($x,-1);
### @n
(scalar(@n) == 1)
or &$report ("xy_to_n($x,-1) array context got ",scalar(@n)," values but should be 1, possibly undef");
}
{
my $path_x_negative = ($path->x_negative ? 1 : 0);
$got_x_negative = ($got_x_negative ? 1 : 0);
if ($path->isa('Math::PlanePath::GosperSide')
|| $path->isa('Math::PlanePath::FlowsnakeCentres')
|| $path->isa('Math::PlanePath::QuintetCentres')
|| $mod eq 'ImaginaryBase,radix=37'
|| $mod eq 'ImaginaryHalf,radix=37'
|| $mod eq 'CubicBase,radix=37'
|| $mod eq 'ComplexPlus,realpart=2'
|| $mod eq 'ComplexPlus,realpart=3'
|| $mod eq 'ComplexPlus,realpart=4'
|| $mod eq 'ComplexPlus,realpart=5'
|| ($mod eq 'GreekKeySpiral' && $limit < 37)
|| ($mod eq 'GreekKeySpiral,turns=3' && $limit < 65)
|| ($mod eq 'GreekKeySpiral,turns=4' && $limit < 101)
|| ($mod eq 'GreekKeySpiral,turns=5' && $limit < 145)
|| ($mod eq 'GreekKeySpiral,turns=6' && $limit < 197)
|| $mod eq 'GreekKeySpiral,turns=7'
|| $mod eq 'GreekKeySpiral,turns=8'
|| $mod eq 'GreekKeySpiral,turns=37'
) {
# these don't get to X negative in small rectangle
$got_x_negative = 1;
}
($path_x_negative == $got_x_negative)
or &$report ("x_negative() $path_x_negative but in rect to n=$limit got $got_x_negative");
}
{
my $path_y_negative = ($path->y_negative ? 1 : 0);
$got_y_negative = ($got_y_negative ? 1 : 0);
if ($path->isa('Math::PlanePath::GosperSide')
|| $path->isa('Math::PlanePath::FlowsnakeCentres')
|| ($mod eq 'GreekKeySpiral' && $limit < 55)
|| ($mod eq 'GreekKeySpiral,turns=3' && $limit < 97)
|| ($mod eq 'GreekKeySpiral,turns=4' && $limit < 151)
|| ($mod eq 'GreekKeySpiral,turns=5' && $limit < 217)
|| ($mod eq 'GreekKeySpiral,turns=6' && $limit < 295)
|| $mod eq 'GreekKeySpiral,turns=7'
|| $mod eq 'GreekKeySpiral,turns=8'
|| $mod eq 'GreekKeySpiral,turns=37'
|| $mod eq 'SquareSpiral,wider=37'
|| $mod eq 'HexSpiral,wider=37'
|| $mod eq 'HexSpiralSkewed,wider=37'
|| ($mod eq 'ImaginaryBase,radix=3' && $limit < 3**3) # first Y negs
|| ($mod eq 'ImaginaryBase,radix=4' && $limit < 4**3)
|| ($mod eq 'ImaginaryBase,radix=5' && $limit < 5**3)
|| ($mod eq 'ImaginaryBase,radix=37' && $limit < 37**3)
|| $mod eq 'CubicBase,radix=37'
|| ($mod eq 'ComplexPlus' && $limit < 32) # first y_neg at N=32
|| $mod eq 'ComplexPlus,realpart=2' # y_neg big
|| $mod eq 'ComplexPlus,realpart=3'
|| $mod eq 'ComplexPlus,realpart=4'
|| $mod eq 'ComplexPlus,realpart=5'
|| $mod eq 'ComplexMinus,realpart=3'
|| $mod eq 'ComplexMinus,realpart=4'
|| $mod eq 'ComplexMinus,realpart=5'
|| ($mod eq 'AnvilSpiral,wider=17' && $limit < 41) # first y_neg at N=41
|| $mod eq 'TerdragonCurve'
|| $mod eq 'TerdragonCurve,arms=2'
|| $mod eq 'TerdragonMidpoint'
|| $mod eq 'TerdragonMidpoint,arms=2'
|| $mod eq 'TerdragonRounded'
|| $mod eq 'TerdragonRounded,arms=2'
|| $mod eq 'TerdragonRounded,arms=3'
|| ($mod eq 'AlternatePaper,arms=5' && $limit < 44) # first y_neg at N=44
|| ($mod eq 'AlternatePaper,arms=8' && $limit < 14) # first y_neg at N=14
|| $mod eq 'R5DragonCurve'
|| $mod eq 'R5DragonMidpoint'
|| $mod eq 'R5DragonMidpoint,arms=2'
) {
# GosperSide and Flowsnake take a long time to get
# to Y negative, not reached by the rectangle
# considered here. ComplexMinus doesn't get there
# on realpart==5 or bigger too.
$got_y_negative = 1;
}
($path_y_negative == $got_y_negative)
or &$report ("y_negative() $path_y_negative but in rect to n=$limit got $got_y_negative");
}
if ($path->figure ne 'circle'
# bit slow
&& ! ($path->isa('Math::PlanePath::Flowsnake'))) {
my $x_min = ($path->x_negative ? - int($rect_limit/2) : -2);
my $y_min = ($path->y_negative ? - int($rect_limit/2) : -2);
my $x_max = $x_min + $rect_limit;
my $y_max = $y_min + $rect_limit;
my $data;
foreach my $x ($x_min .. $x_max) {
foreach my $y ($y_min .. $y_max) {
$data->{$y}->{$x} = $path->xy_to_n ($x, $y);
}
}
#### $data
# MyTestHelpers::diag ("rect check ...");
foreach my $y1 ($y_min .. $y_max) {
foreach my $y2 ($y1 .. $y_max) {
foreach my $x1 ($x_min .. $x_max) {
my $min;
my $max;
foreach my $x2 ($x1 .. $x_max) {
my @col = map {$data->{$_}->{$x2}} $y1 .. $y2;
@col = grep {defined} @col;
$min = List::Util::min (grep {defined} $min, @col);
$max = List::Util::max (grep {defined} $max, @col);
my $want_min = (defined $min ? $min : 1);
my $want_max = (defined $max ? $max : 0);
### @col
### rect: "$x1,$y1 $x2,$y2 expect N=$want_min..$want_max"
foreach my $x_swap (0, 1) {
my ($x1,$x2) = ($x_swap ? ($x1,$x2) : ($x2,$x1));
foreach my $y_swap (0, 1) {
my ($y1,$y2) = ($y_swap ? ($y1,$y2) : ($y2,$y1));
my ($got_min, $got_max)
= $path->rect_to_n_range ($x1,$y1, $x2,$y2);
defined $got_min
or &$report ("rect_to_n_range($x1,$y1, $x2,$y2) got_min undef");
defined $got_max
or &$report ("rect_to_n_range($x1,$y1, $x2,$y2) got_max undef");
if ($got_max >= $got_min) {
$got_min >= $n_start
or $rect_before_n_start{$class}
or &$report ("rect_to_n_range() got_min=$got_min is before n_start=$n_start");
}
if (! defined $min || ! defined $max) {
if (! $rect_exact_hi{$class}) {
next; # outside
}
}
unless ($rect_exact{$class}
? $got_min == $want_min
: $got_min <= $want_min) {
### $x1
### $y1
### $x2
### $y2
### got: $path->rect_to_n_range ($x1,$y1, $x2,$y2)
### $want_min
### $want_max
### $got_min
### $got_max
### @col
### $data
&$report ("rect_to_n_range($x1,$y1, $x2,$y2) bad min got_min=$got_min want_min=$want_min".(defined $min ? '' : '[nomin]')
);
}
unless ($rect_exact_hi{$class}
? $got_max == $want_max
: $got_max >= $want_max) {
&$report ("rect_to_n_range($x1,$y1, $x2,$y2 ) bad max got $got_max want $want_max".(defined $max ? '' : '[nomax]'));
}
}
}
}
}
}
}
if ($path->can('xy_is_visited') != Math::PlanePath->can('xy_is_visited')) {
# MyTestHelpers::diag ("xy_is_visited() check ...");
foreach my $y ($y_min .. $y_max) {
foreach my $x ($x_min .. $x_max) {
my $got_visited = ($path->xy_is_visited($x,$y) ? 1 : 0);
my $want_visited = (defined($data->{$y}->{$x}) ? 1 : 0);
unless ($got_visited == $want_visited) {
&$report ("xy_is_visited($x,$y) got $got_visited want $want_visited");
}
}
}
}
}
my $is_a_tree;
{
my @n_children = $path->tree_n_children($n_start);
if (@n_children) {
$is_a_tree = 1;
}
}
my $num_children_minimum = $path->tree_num_children_minimum;
my $num_children_maximum = $path->tree_num_children_maximum;
($num_children_maximum >= $num_children_minimum)
or &$report ("tree_num_children_maximum() is ",$num_children_maximum,
"expect >= tree_num_children_minimum() is ",$num_children_minimum);
my @num_children_list = $path->tree_num_children_list;
my $num_children_list_str = join(',',@num_children_list);
my %num_children_hash;
@num_children_hash{@num_children_list} = (); # hash slice
@num_children_list >= 1
or &$report ("tree_num_children_list() is empty");
$num_children_list[0] == $num_children_minimum
or &$report ("tree_num_children_list() first != minimum");
$num_children_list[-1] == $num_children_maximum
or &$report ("tree_num_children_list() last != maximum");
join(',',sort {$a<=>$b} @num_children_list) eq $num_children_list_str
or &$report ("tree_num_children_list() not sorted");
# tree_any_leaf() is the same as tree_num_children_minimum()==0
my $any_leaf = $path->tree_any_leaf;
((!!$any_leaf) == ($num_children_minimum==0))
or &$report ("tree_any_leaf() is ",$any_leaf," but tree_num_children_minimum() is ",$num_children_minimum);
my $num_roots = $path->tree_num_roots;
if ($is_a_tree) {
$num_roots > 0
or &$report ("tree_num_roots() should be > 0, got ", $num_roots);
} else {
$num_roots == 0
or &$report ("tree_num_roots() should be 0 for non-tree, got ", $num_roots);
}
my @root_n_list = $path->tree_root_n_list;
my $root_n_list_str = join(',',@root_n_list);
scalar(@root_n_list) == $num_roots
or &$report ("tree_root_n_list() $root_n_list_str expected num_roots=$num_roots many values");
my %root_n_list;
foreach my $root_n (@root_n_list) {
if (exists $root_n_list{$root_n}) {
&$report ("tree_root_n_list() duplicate $root_n in list $root_n_list_str");
}
$root_n_list{$root_n} = 1;
}
### tree_n_root() of each ...
my $have_class_tree_n_root
= ($path->can('tree_n_root') != Math::PlanePath->can('tree_n_root'));
if ($have_class_tree_n_root) {
MyTestHelpers::diag ("tree_n_root() specific implementation ...");
}
foreach my $n ($n_start .. $n_start+$limit) {
my $root_n = $path->tree_n_root($n);
if ($is_a_tree) {
if (! defined $root_n || ! $root_n_list{$root_n}) {
&$report ("tree_n_root($n) got ",$root_n," is not a root ($root_n_list_str)");
}
if ($have_class_tree_n_root) {
my $root_n_by_search = $path->Math::PlanePath::tree_n_root($n);
$root_n == $root_n_by_search
or &$report ("tree_n_root($n) got ",$root_n," but by search is ",$root_n_by_search);
}
} else {
if (defined $root_n) {
&$report ("tree_n_root($n) got ",$root_n," expected undef for non-tree");
}
}
}
### tree_n_children before n_start ...
foreach my $n ($n_start-5 .. $n_start-1) {
{
my @n_children = $path->tree_n_children($n);
(@n_children == 0)
or &$report ("tree_n_children($n) before n_start=$n_start unexpectedly got ",scalar(@n_children)," values:",@n_children);
}
{
my $num_children = $path->tree_n_num_children($n);
if (defined $num_children) {
&$report ("tree_n_num_children($n) before n_start=$n_start unexpectedly $num_children not undef");
}
}
}
### tree_n_parent() before n_start ...
foreach my $n ($n_start-5 .. $n_start) {
my $n_parent = $path->tree_n_parent($n);
if (defined $n_parent) {
&$report ("tree_n_parent($n) <= n_start=$n_start unexpectedly got parent ",$n_parent);
}
}
### tree_n_children() look at tree_n_parent of each ...
{
my %unseen_num_children = %num_children_hash;
foreach my $n ($n_start .. $n_start+$limit,
($path->isa('Math::PlanePath::OneOfEight')
? (37, # first with 2 children in parts=4
58) # first with 3 children in parts=4
: ())) {
### $n
my @n_children = $path->tree_n_children($n);
### @n_children
my $num_children = scalar(@n_children);
exists $num_children_hash{$num_children}
or &$report ("tree_n_children($n)=$num_children not in tree_num_children_list()=$num_children_list_str");
delete $unseen_num_children{$num_children};
foreach my $n_child (@n_children) {
my $got_n_parent = $path->tree_n_parent($n_child);
($got_n_parent == $n)
or &$report ("tree_n_parent($n_child) got $got_n_parent want $n");
}
}
if (%unseen_num_children) {
&$report ("tree_num_children_list() values not seen: ",
join(',',sort {$a<=>$b} keys %unseen_num_children),
" of total=$num_children_list_str");
}
}
### tree_n_to_depth() before n_start ...
foreach my $n ($n_start-5 .. $n_start-1) {
my $depth = $path->tree_n_to_depth($n);
if (defined $depth) {
&$report ("tree_n_to_depth($n) < n_start=$n_start unexpectedly got depth ",$depth);
}
}
my @depth_to_width_by_count;
my @depth_to_n_seen;
my @depth_to_n_end_seen;
if ($path->can('tree_n_to_depth')
!= Math::PlanePath->can('tree_n_to_depth')) {
### tree_n_to_depth() vs count up by parents ...
# MyTestHelpers::diag ($mod, ' tree_n_to_depth()');
foreach my $n ($n_start .. $n_start+$limit) {
my $want_depth = path_tree_n_to_depth_by_parents($path,$n);
my $got_depth = $path->tree_n_to_depth($n);
if (! defined $got_depth || ! defined $want_depth
|| $got_depth != $want_depth) {
&$report ("tree_n_to_depth($n) got ",$got_depth," want ",$want_depth);
}
if ($got_depth >= 0 && $got_depth <= $depth_limit) {
$depth_to_width_by_count[$got_depth]++;
if (! defined $depth_to_n_seen[$got_depth]) {
$depth_to_n_seen[$got_depth] = $n;
}
$depth_to_n_end_seen[$got_depth] = $n;
}
}
}
if ($path->can('tree_n_to_subheight')
!= Math::PlanePath->can('tree_n_to_subheight')) {
### tree_n_to_subheight() vs search downwards ...
# MyTestHelpers::diag ($mod, ' tree_n_to_subheight()');
foreach my $n ($n_start .. $n_start+$limit) {
my $want_height = path_tree_n_to_subheight_by_search($path,$n);
my $got_height = $path->tree_n_to_subheight($n);
if (! equal($got_height,$want_height)) {
&$report ("tree_n_to_subheight($n) got ",$got_height," want ",$want_height);
}
}
}
if ($path->can('_EXPERIMENTAL__tree_n_to_leafdist')
# != Math::PlanePath->can('_EXPERIMENTAL__tree_n_to_leafdist')
) {
### _EXPERIMENTAL__tree_n_to_leafdist() vs search downwards ...
# MyTestHelpers::diag ($mod, ' _EXPERIMENTAL__tree_n_to_leafdist()');
foreach my $n ($n_start .. $n_start+$limit) {
my $want_height = path_tree_n_to_leafdist_by_search($path,$n);
my $got_height = $path->_EXPERIMENTAL__tree_n_to_leafdist($n);
if (! equal($got_height,$want_height)) {
&$report ("_EXPERIMENTAL__tree_n_to_leafdist($n) got ",$got_height," want ",$want_height);
}
}
}
### tree_depth_to_n() on depth<0 ...
foreach my $depth (-2 .. -1) {
foreach my $method ('tree_depth_to_n','tree_depth_to_n_end') {
my $n = $path->$method($depth);
if (defined $n) {
&$report ("$method($depth) unexpectedly got n=",$n);
}
}
{
my @ret = $path->tree_depth_to_n_range($depth);
scalar(@ret) == 0
or &$report ("tree_depth_to_n_range($depth) not an empty return");
}
}
### tree_depth_to_n() ...
if ($is_a_tree) {
my $n_rows_are_contiguous = path_tree_n_rows_are_contiguous($path);
foreach my $depth (0 .. $depth_limit) {
my $n = $path->tree_depth_to_n($depth);
if (! defined $n) {
&$report ("tree_depth_to_n($depth) should not be undef");
next;
}
if ($n != int($n)) {
&$report ("tree_depth_to_n($depth) not an integer: ",$n);
next;
}
if ($n <= $limit) {
my $want_n = $depth_to_n_seen[$depth];
if (! defined $want_n || $n != $want_n) {
&$report ("tree_depth_to_n($depth)=$n but depth_to_n_seen[$depth]=",$want_n);
}
}
my $n_end = $path->tree_depth_to_n_end($depth);
$n_end >= $n
or &$report ("tree_depth_to_n_end($depth) $n_end less than tree_depth_to_n() start $n");
my ($n_range_lo, $n_range_hi) = $path->tree_depth_to_n_range($depth);
$n_range_lo == $n
or &$report ("tree_depth_to_n_range($depth) $n_range_lo != tree_depth_to_n() start $n");
$n_range_hi == $n_end
or &$report ("tree_depth_to_n_range($depth) $n_range_hi != tree_depth_to_n_end() start $n_end");
{
my $got_depth = $path->tree_n_to_depth($n);
if (! defined $got_depth || $got_depth != $depth) {
&$report ("tree_depth_to_n($depth)=$n reverse got_depth=",$got_depth);
}
}
{
my $got_depth = $path->tree_n_to_depth($n-1);
if (defined $got_depth && $got_depth >= $depth) {
&$report ("tree_depth_to_n($depth)=$n reverse of n-1 got_depth=",$got_depth);
}
}
{
my $got_depth = $path->tree_n_to_depth($n_end);
if (! defined $got_depth || $got_depth != $depth) {
&$report ("tree_depth_to_n_end($depth)=$n_end reverse n_end got_depth=",$got_depth);
}
}
{
my $got_depth = $path->tree_n_to_depth($n_end+1);
if (defined $got_depth && $got_depth <= $depth) {
&$report ("tree_depth_to_n($depth)=$n reverse of n_end+1 got_depth=",$got_depth);
}
}
if ($n_end <= $limit) {
my $got_width = $path->tree_depth_to_width($depth);
my $want_width = $depth_to_width_by_count[$depth] || 0;
if ($got_width != $want_width) {
&$report ("tree_depth_to_width($depth)=$got_width but counting want=$want_width");
}
}
}
}
### done mod: $mod
}
ok ($good, 1);
}
# Return true if the rows of the tree are numbered contiguously, so each row
# starts immediately following the previous with no overlapping.
sub path_tree_n_rows_are_contiguous {
my ($path) = @_;
foreach my $depth (0 .. 10) {
my $n_end = $path->tree_depth_to_n_end($depth);
my $n_next = $path->tree_depth_to_n($depth+1);
if ($n_next != $n_end+1) {
return 0;
}
}
return 1;
}
# Unused for now.
#
# sub path_tree_depth_to_width_by_count {
# my ($path, $depth) = @_;
# ### path_tree_depth_to_width_by_count(): $depth
# my $width = 0;
# my ($n_lo, $n_hi) = $path->tree_depth_to_n_range($depth);
# ### $n_lo
# ### $n_hi
# foreach my $n ($n_lo .. $n_hi) {
# ### d: $path->tree_n_to_depth($n)
# $width += ($path->tree_n_to_depth($n) == $depth);
# }
# ### $width
# return $width;
# }
sub path_tree_n_to_depth_by_parents {
my ($path, $n) = @_;
if ($n < $path->n_start) {
return undef;
}
my $depth = 0;
for (;;) {
my $parent_n = $path->tree_n_parent($n);
last if ! defined $parent_n;
if ($parent_n >= $n) {
die "Oops, tree parent $parent_n >= child $n in ", ref $path;
}
$n = $parent_n;
$depth++;
}
return $depth;
}
# use Smart::Comments;
use constant SUBHEIGHT_SEARCH_LIMIT => 50;
sub path_tree_n_to_subheight_by_search {
my ($path, $n, $limit) = @_;
if ($path->isa('Math::PlanePath::HTree') && is_pow2($n)) {
return undef; # infinite
}
if (! defined $limit) { $limit = SUBHEIGHT_SEARCH_LIMIT; }
if ($limit <= 0) {
return undef; # presumed infinite
}
if (! exists $path->{'path_tree_n_to_subheight_by_search__cache'}->{$n}) {
my @children = $path->tree_n_children($n);
my $height = 0;
foreach my $n_child (@children) {
my $h = path_tree_n_to_subheight_by_search($path,$n_child,$limit-1);
if (! defined $h) {
$height = undef; # infinite
last;
}
$h++;
if ($h >= $height) {
$height = $h; # new bigger subheight among the children
}
}
### maximum is: $height
if (defined $height || $limit >= SUBHEIGHT_SEARCH_LIMIT*4/5) {
### set cache: "n=$n ".($height//'[undef]')
$path->{'path_tree_n_to_subheight_by_search__cache'}->{$n} = $height;
### cache: $path->{'path_tree_n_to_subheight_by_search__cache'}
}
}
### path_tree_n_to_subheight_by_search(): "n=$n"
return $path->{'path_tree_n_to_subheight_by_search__cache'}->{$n};
# my @n = ($n);
# my $height = 0;
# my @pending = ($n);
# for (;;) {
# my $n = pop @pending;
# @n = map {} @n
# or return $height;
#
# if (defined my $h = $path->{'path_tree_n_to_subheight_by_search__cache'}->{$n}) {
# return $height + $h;
# }
# @n = map {$path->tree_n_children($_)} @n
# or return $height;
# $height++;
# if (@n > 200 || $height > 200) {
# return undef; # presumed infinite
# }
# }
}
# no Smart::Comments;
sub path_tree_n_to_leafdist_by_search {
my ($path, $n, $limit) = @_;
if (! defined $limit) { $limit = SUBHEIGHT_SEARCH_LIMIT; }
### path_tree_n_to_leafdist_by_search(): "n=$n limit=$limit"
if ($limit <= 0) {
return undef; # presumed infinite
}
if (! exists $path->{'path_tree_n_to_leafdist_by_search__cache'}->{$n}) {
my @children = $path->tree_n_children($n);
my $leafdist = 0;
if (@children) {
my @min;
foreach my $child_n (@children) {
my $child_leafdist = path_tree_n_to_leafdist_by_search
($path, $child_n, List::Util::min(@min,$limit-1));
if (defined $child_leafdist) {
if ($child_leafdist == 0) {
# child is a leaf, distance to it is 1
@min = (1);
last;
}
push @min, $child_leafdist+1;
}
}
$leafdist = List::Util::min(@min);
### for: "n=$n min of ".join(',',@min)." children=".join(',',@children)." gives ",$leafdist
} else {
### for: "n=$n is a leaf node"
}
if (defined $leafdist || $limit >= SUBHEIGHT_SEARCH_LIMIT*4/5) {
$path->{'path_tree_n_to_leafdist_by_search__cache'}->{$n} = $leafdist;
}
}
### path_tree_n_to_leafdist_by_search(): "n=$n"
return $path->{'path_tree_n_to_leafdist_by_search__cache'}->{$n};
}
# no Smart::Comments;
sub equal {
my ($x,$y) = @_;
return ((! defined $x && ! defined $y)
|| (defined $x && defined $y && $x == $y));
}
use POSIX 'fmod';
sub gcd {
my ($x,$y) = @_;
$x = abs($x);
$y = abs($y);
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
# hack to recognise 1/3 from KochSnowflakes
if ($x == 1 && $y == 1/3) {
return $y;
}
if ($x == 0) {
return $y;
}
if ($y > $x) {
$y = fmod($y,$x);
}
for (;;) {
### assert: $x >= 1
if ($y == 0) {
return $x; # gcd(x,0)=x
}
if ($y < 0.00001) {
return 0;
}
($x,$y) = ($y, fmod($x,$y));
}
}
sub is_pow2 {
my ($n) = @_;
my ($pow,$exp) = round_down_pow ($n, 2);
return ($n == $pow);
}
#------------------------------------------------------------------------------
# generic
sub coderef_is_const {
my ($coderef) = @_;
# FIXME: is not quite right? Is XSUBANY present on ALIAS: xsubs too?
require B;
return defined(B::svref_2object(\&coderef_is_const)->XSUBANY);
}
CHECK {
# my $coderef_is_const_check = 1;
use constant coderef_is_const_check => 1;
coderef_is_const(\&coderef_is_const_check) or die;
}
exit 0;
Math-PlanePath-113/xt/0-Test-YAML-Meta.t 0000755 0001750 0001750 00000003336 12251252266 015232 0 ustar gg gg #!/usr/bin/perl -w
# 0-Test-YAML-Meta.t -- run Test::CPAN::Meta::YAML if available
# Copyright 2009, 2010, 2011, 2013 Kevin Ryde
# 0-Test-YAML-Meta.t is shared by several distributions.
#
# 0-Test-YAML-Meta.t 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, or (at your option) any later
# version.
#
# 0-Test-YAML-Meta.t 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 file. If not, see .
use 5.004;
use strict;
use Test::More;
my $meta_filename = 'META.yml';
unless (-e $meta_filename) {
plan skip_all => "$meta_filename doesn't exist -- assume this is a working directory not a dist";
}
plan tests => 3;
SKIP: {
eval { require CPAN::Meta::Validator; 1 }
or skip "due to CPAN::Meta::Validator not available -- $@";
eval { require YAML; 1 }
or skip "due to YAML module not available -- $@", 1;
my $struct = YAML::LoadFile ($meta_filename);
my $cmv = CPAN::Meta::Validator->new($struct);
ok ($cmv->is_valid);
if (! $cmv->is_valid) {
diag "CPAN::Meta::Validator errors:";
foreach ($cmv->errors) { diag $_; }
}
}
{
# Test::CPAN::Meta::YAML version 0.15 for upper case "optional_features" names
#
eval 'use Test::CPAN::Meta::YAML 0.15; 1'
or plan skip_all => "due to Test::CPAN::Meta::YAML 0.15 not available -- $@";
Test::CPAN::Meta::YAML::meta_spec_ok('META.yml');
}
exit 0;
Math-PlanePath-113/xt/PixelRings-image.t 0000644 0001750 0001750 00000010613 12136177167 015677 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use Math::PlanePath::PixelRings;
my $test_count = (tests => 2)[1];
plan tests => $test_count;
if (! eval 'use Image::Base 1.09; 1') { # version 1.09 for ellipse fixes
MyTestHelpers::diag ('skip due to Image::Base 1.09 not available -- ',$@);
foreach (1 .. $test_count) {
skip ('due to no Image::Base 1.09', 1, 1);
}
exit 0;
}
# uncomment this to run the ### lines
#use Smart::Comments;
sub dump_coords {
my ($href) = @_;
my $x_min = 0;
my $y_min = 0;
foreach my $key (keys %$href) {
my ($x,$y) = split /,/, $key;
if ($x < $x_min) { $x_min = $x; }
if ($y < $y_min) { $y_min = $y; }
}
my @rows;
foreach my $key (keys %$href) {
my ($x,$y) = split /,/, $key;
$rows[$y-$y_min]->[$x-$x_min] = '*';
}
foreach my $row (reverse @rows) {
my $str = '';
if ($row) {
foreach my $char (@$row) {
if ($char) {
$str .= " $char";
} else {
$str .= " ";
}
}
}
MyTestHelpers::diag ($str);
}
}
my %image_coords;
my $offset = 100;
{
package MyImage;
use vars '@ISA';
@ISA = ('Image::Base');
sub new {
my $class = shift;
return bless {@_}, $class;
}
sub xy {
my ($self, $x, $y, $colour) = @_;
$x -= $offset;
$y -= $offset;
### image_coords: "$x,$y"
$image_coords{"$x,$y"} = 1;
}
}
#------------------------------------------------------------------------------
# _cumul_extend()
{
my $path = Math::PlanePath::PixelRings->new;
my $image = MyImage->new;
my $good = 1;
my $limit = 500;
foreach my $r (1 .. $limit) {
%image_coords = ();
$image->ellipse (-$r+$offset,-$r+$offset, $r+$offset,$r+$offset, 'white');
my $image_count = scalar(@{[keys %image_coords]});
Math::PlanePath::PixelRings::_cumul_extend($path);
my $got = $path->{'cumul'}->[$r+1];
my $want = $path->{'cumul'}->[$r] + $image_count;
if ($got != $want) {
$good = 0;
MyTestHelpers::diag ("_cumul_extend() r=$r wrong: want=$want got=$got");
}
}
ok ($good, 1, "_cumul_extend() to $limit");
}
#------------------------------------------------------------------------------
# coords
{
my $path = Math::PlanePath::PixelRings->new;
my $image = MyImage->new;
my $n = 1;
my $good = 1;
my $limit = 100;
foreach my $r (0 .. $limit) {
%image_coords = ();
$image->ellipse (-$r+$offset,-$r+$offset, $r+$offset,$r+$offset, 'white');
my $image_count = scalar(@{[keys %image_coords]});
### $image_count
### from n: $n
my %path_coords;
while ($image_count--) {
my ($x,$y) = $path->n_to_xy($n++);
# perl 5.6.0 through 5.6.2 ends up giving "-0" when stringizing (as of
# the code in PixelRings version 19), avoid that so the hash keys
# compare with "eq" successfully
$x = "$x";
$y = "$y";
if ($x eq '-0') { $x = '0'; }
if ($y eq '-0') { $y = '0'; }
### path_coords: "$x,$y"
$path_coords{"$x,$y"} = 1;
}
### %image_coords
### %path_coords
if (! eq_hash (\%path_coords, \%image_coords)) {
MyTestHelpers::diag ("Wrong coords at r=$r");
MyTestHelpers::diag ("image: ", join(',', sort keys %image_coords));
MyTestHelpers::diag ("path: ", join(',', sort keys %path_coords));
dump_coords (\%image_coords);
dump_coords (\%path_coords);
$good = 0;
}
}
ok ($good, 1, 'n_to_xy() compared to image->ellipse()');
}
sub eq_hash {
my ($x, $y) = @_;
foreach my $key (keys %$x) {
if (! exists $y->{$key}) {
return 0;
}
}
foreach my $key (keys %$y) {
if (! exists $x->{$key}) {
return 0;
}
}
return 1;
}
exit 0;
Math-PlanePath-113/xt/0-META-read.t 0000755 0001750 0001750 00000010715 12136177162 014330 0 ustar gg gg #!/usr/bin/perl -w
# 0-META-read.t -- check META.yml can be read by various YAML modules
# Copyright 2009, 2010, 2011, 2012, 2013 Kevin Ryde
# 0-META-read.t is shared among several distributions.
#
# 0-META-read.t 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, or (at your option) any later
# version.
#
# 0-META-read.t 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 file. If not, see .
use 5.005;
use strict;
use Test::More;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# When some of META.yml is generated by explicit text in Makefile.PL it can
# be easy to make a mistake in the syntax, or indentation, etc, so the idea
# here is to check it's readable from some of the YAML readers.
#
# The various readers differ in how strictly they look at the syntax.
# There's no attempt here to say one of them is best or tightest or
# whatever, just see that they all work.
#
# See 0-Test-YAML-Meta.t for Test::YAML::Meta which looks into field
# contents, as well as maybe the YAML formatting.
my $meta_filename;
# allow for ancient perl, maybe
eval { require FindBin; 1 } # new in 5.004
or plan skip_all => "FindBin not available -- $@";
eval { require File::Spec; 1 } # new in 5.005
or plan skip_all => "File::Spec not available -- $@";
diag "FindBin $FindBin::Bin";
$meta_filename = File::Spec->catfile
($FindBin::Bin, File::Spec->updir, 'META.yml');
-e $meta_filename
or plan skip_all => "$meta_filename doesn't exist -- assume this is a working directory not a dist";
plan tests => 5;
SKIP: {
eval { require YAML; 1 }
or skip "due to YAML module not available -- $@", 1;
my $ok = eval { YAML::LoadFile ($meta_filename); 1 }
or diag "YAML::LoadFile() error -- $@";
ok ($ok, "Read $meta_filename with YAML module");
}
# YAML 0.68 is in fact YAML::Old, or something weird -- don't think they can
# load together
#
# SKIP: {
# eval { require YAML::Old; 1 }
# or skip 'due to YAML::Old not available -- $@', 1;
#
# eval { YAML::Old::LoadFile ($meta_filename) };
# is ($@, '',
# "Read $meta_filename with YAML::Old");
# }
SKIP: {
eval { require YAML::Syck; 1 }
or skip "due to YAML::Syck not available -- $@", 1;
my $ok = eval { YAML::Syck::LoadFile ($meta_filename); 1 }
or diag "YAML::Syck::LoadFile() error -- $@";
ok ($ok, "Read $meta_filename with YAML::Syck");
}
SKIP: {
eval { require YAML::Tiny; 1 }
or skip "due to YAML::Tiny not available -- $@", 1;
my $ok = eval { YAML::Tiny->read ($meta_filename); 1 }
or diag "YAML::Tiny->read() error -- $@";
ok ($ok, "Read $meta_filename with YAML::Tiny");
}
SKIP: {
eval { require YAML::XS; 1 }
or skip "due to YAML::XS not available -- $@", 1;
my $ok = eval { YAML::XS::LoadFile ($meta_filename); 1 }
or diag "YAML::XS::LoadFile() error -- $@";
ok ($ok, "Read $meta_filename with YAML::XS");
}
# Parse::CPAN::Meta describes itself for use on "typical" META.yml, so not
# sure if demanding it works will more exercise its subset of yaml than the
# correctness of our META.yml. At any rate might like to know if it fails,
# so as to avoid tricky yaml for everyone's benefit, maybe.
#
SKIP: {
eval { require Parse::CPAN::Meta; 1 }
or skip "due to Parse::CPAN::Meta not available -- $@", 1;
my $ok = eval { Parse::CPAN::Meta::LoadFile ($meta_filename); 1 }
or diag "Parse::CPAN::Meta::LoadFile() error -- $@";
ok ($ok, "Read $meta_filename with Parse::CPAN::Meta::LoadFile");
}
# Data::YAML::Reader 0.06 doesn't like header "--- #YAML:1.0" with the #
# part produced by other YAML writers, so skip for now
#
# SKIP: {
# eval { require Data::YAML::Reader; 1 }
# or skip 'due to Data::YAML::Reader not available -- $@', 1;
#
# my $reader = Data::YAML::Reader->new;
# open my $fh, '<', $meta_filename
# or die "Cannot open $meta_filename";
# my $str = do { local $/=undef; <$fh> };
# close $fh or die;
#
# # if ($str !~ /\.\.\.$/) {
# # $str .= "...";
# # }
# my @lines = split /\n/, $str;
# push @lines, "...";
# use Data::Dumper;
# print Dumper(\@lines);
#
# # { local $,="\n"; print @lines,"\n"; }
exit 0;
Math-PlanePath-113/xt/ChanTree-slow.t 0000644 0001750 0001750 00000007170 12136177167 015212 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
plan tests => 22;;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use Math::PlanePath::CoprimeColumns;
*_coprime = \&Math::PlanePath::CoprimeColumns::_coprime;
use Math::PlanePath::GcdRationals;
*_gcd = \&Math::PlanePath::GcdRationals::_gcd;
# uncomment this to run the ### lines
#use Smart::Comments;
require Math::PlanePath::ChanTree;
#------------------------------------------------------------------------------
# n_to_xy() reversal
{
require Math::PlanePath::GcdRationals;
foreach my $k (3 .. 7) {
foreach my $reduced (0, 1) {
my $path = Math::PlanePath::ChanTree->new (k => $k,
reduced => $reduced);
foreach my $n ($path->n_start .. 500) {
my ($x,$y) = $path->n_to_xy($n);
my $rev = $path->xy_to_n($x,$y);
if (! defined $rev || $rev != $n) {
$rev = (defined $rev ? $rev : 'undef');
die "k=$k reduced=$reduced n_to_xy($n)=$x,$y but reverse xy_to_n($x,$y) is rev=$rev";
}
if ($reduced) {
my $gcd = Math::PlanePath::GcdRationals::_gcd($x,$y);
if ($gcd > 1) {
die "k=$k reduced=$reduced n_to_xy($n)=$x,$y common factor $gcd";
}
}
}
ok ($k, $k);
}
}
}
#------------------------------------------------------------------------------
# block of points
eval 'use Math::BigInt try=>q{GMP}; 1'
|| eval 'use Math::BigInt; 1'
|| die;
{
my $size = 100;
foreach my $k (2 .. 7) {
foreach my $reduced (0, 1) {
my $path = Math::PlanePath::ChanTree->new (k => $k,
reduced => $reduced);
my %seen_n;
foreach my $x (1 .. $size) {
foreach my $y (1 .. $size) {
my $n = $path->xy_to_n(Math::BigInt->new($x),
Math::BigInt->new($y));
if ($reduced) {
if (is_reduced_xy($k,$x,$y)) {
if (! defined $n) {
die "k=$k reduced=$reduced xy_to_n($x,$y) is reduced point but n=undef";
}
} else {
if (defined $n) {
my $gcd = Math::PlanePath::GcdRationals::_gcd($x,$y);
die "k=$k reduced=$reduced xy_to_n($x,$y) is not reduced point (gcd=$gcd) but still have n=$n";
}
}
}
if (defined $n) {
if ($seen_n{$n}) {
die "k=$k xy_to_n($x,$y) is n=$n, but previously xy_to_n($seen_n{$n}) was n=$n";
}
$seen_n{$n} = "$x,$y";
}
}
}
ok ($k, $k);
}
}
}
sub is_reduced_xy {
my ($k, $x, $y) = @_;
if (! _coprime($x,$y)) {
return 0;
}
if (($k & 1) && is_both_odd($x,$y)) {
return 0;
}
return 1;
}
sub is_both_odd {
my ($x, $y) = @_;
return ($x % 2) && ($y % 2);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/slow/ 0002755 0001750 0001750 00000000000 12255673733 013335 5 ustar gg gg Math-PlanePath-113/xt/slow/NumSeq-PlanePathCoord.t 0000644 0001750 0001750 00000217750 12253140273 017567 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Test;
use Data::Float 'pos_infinity';
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use Math::PlanePath::Base::Generic
'is_infinite';
# uncomment this to run the ### lines
# use Smart::Comments '###';
my $test_count = (tests => 1045)[1];
plan tests => $test_count;
if (! eval { require Math::NumSeq; 1 }) {
MyTestHelpers::diag ('skip due to Math::NumSeq not available -- ',$@);
foreach (1 .. $test_count) {
skip ('due to no Math::NumSeq', 1, 1);
}
exit 0;
}
require Math::NumSeq::PlanePathCoord;
sub want_planepath {
my ($planepath) = @_;
# return 0 unless $planepath =~ /HTree/;
# return 0 unless $planepath =~ /DiagonalRationals/;
# return 0 unless $planepath =~ /FactorRationals/;
# return 0 unless $planepath =~ /MultipleRings/;
return 1;
}
sub want_coordinate {
my ($type) = @_;
# return 0 unless $type =~ /sumabs|absdiff/i;
# return 0 unless $type =~ /d[XY]/;
# return 0 unless $type =~ /^dAbsDiff/;
# return 0 unless $type =~ /RSquared|Radius/;
# return 0 unless $type =~ /Left|Right|LSR|SLR|SRL/;
# return 0 unless $type =~ /Dir4|Dir6/;
# return 0 unless $type =~ /LeafDistance/;
return 0 unless $type =~ /Min|Max/;
# return 0 unless $type =~ /dSum|dDiffXY|Absd|d[XY]/;
# return 0 unless $type =~ /^(X|Y|Sum|DiffXY|dX|dY|AbsdX|AbsdY|dSum|dDiffXY|Dir4)$/;
# return 0 unless $type =~ /^(X|Y|Sum|DiffXY|DiffYX)$/;
return 1;
}
#------------------------------------------------------------------------------
# characteristic()
foreach my $elem
(['increasing',0 ], # default SquareSpiral X not monotonic
['non_decreasing', 1, planepath => 'Hypot', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'Hypot', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'HypotOctant', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'HypotOctant', coordinate_type => 'RSquared' ],
['smaller', 1, planepath => 'SquareSpiral', coordinate_type => 'X' ],
['smaller', 1, planepath => 'SquareSpiral', coordinate_type => 'RSquared' ],
['smaller', 0, planepath => 'MultipleRings,step=0', coordinate_type => 'RSquared' ],
['smaller', 0, planepath => 'MultipleRings,step=1', coordinate_type => 'RSquared' ],
['smaller', 1, planepath => 'MultipleRings,step=2', coordinate_type => 'RSquared' ],
['increasing', 1, planepath => 'TheodorusSpiral', coordinate_type => 'Radius' ],
['increasing', 1, planepath => 'TheodorusSpiral', coordinate_type => 'RSquared' ],
['non_decreasing', 1, planepath => 'TheodorusSpiral', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'TheodorusSpiral', coordinate_type => 'RSquared' ],
['smaller', 1, planepath => 'TheodorusSpiral', coordinate_type => 'Radius' ],
['smaller', 0, planepath => 'TheodorusSpiral', coordinate_type => 'RSquared' ],
['increasing', 1, planepath => 'VogelFloret', coordinate_type => 'Radius' ],
['increasing', 1, planepath => 'VogelFloret', coordinate_type => 'RSquared' ],
['non_decreasing', 1, planepath => 'VogelFloret', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'VogelFloret', coordinate_type => 'RSquared' ],
['smaller', 1, planepath => 'VogelFloret', coordinate_type => 'Radius' ],
['smaller', 0, planepath => 'VogelFloret', coordinate_type => 'RSquared' ],
['increasing', 1, planepath => 'SacksSpiral', coordinate_type => 'Radius' ],
['increasing', 1, planepath => 'SacksSpiral', coordinate_type => 'RSquared' ],
['non_decreasing', 1, planepath => 'SacksSpiral', coordinate_type => 'Radius' ],
['non_decreasing', 1, planepath => 'SacksSpiral', coordinate_type => 'RSquared' ],
['smaller', 1, planepath => 'SacksSpiral', coordinate_type => 'Radius' ],
['smaller', 0, planepath => 'SacksSpiral', coordinate_type => 'RSquared' ],
) {
my ($key, $want, @parameters) = @$elem;
my $seq = Math::NumSeq::PlanePathCoord->new (@parameters);
ok ($seq->characteristic($key) ? 1 : 0, $want,
"characteristic($key) on ".join(', ',@parameters));
}
#------------------------------------------------------------------------------
# values_min(), values_max()
foreach my $elem
([undef,undef, planepath => 'SquareSpiral' ], # default coordinate_type=>X
[0,undef, planepath => 'SquareSpiral', coordinate_type => 'Radius' ],
[0,undef, planepath => 'SquareSpiral', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'HilbertCurve', coordinate_type => 'X' ],
[0,undef, planepath => 'HilbertCurve', coordinate_type => 'Y' ],
[0,undef, planepath => 'HilbertCurve', coordinate_type => 'Sum' ],
[0,undef, planepath => 'HilbertCurve', coordinate_type => 'Product' ],
[undef,undef, planepath => 'CellularRule54', coordinate_type => 'X' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'Y' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'Sum' ],
[undef,undef, planepath => 'CellularRule54', coordinate_type => 'Product' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'Radius' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'RSquared' ],
[undef,0, planepath => 'CellularRule54', coordinate_type => 'DiffXY' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'CellularRule54', coordinate_type => 'AbsDiff' ],
[undef,undef, planepath => 'CellularRule190', coordinate_type => 'X' ],
[0,undef, planepath => 'CellularRule190', coordinate_type => 'Y' ],
[0,undef, planepath => 'CellularRule190', coordinate_type => 'Sum' ],
[undef,undef, planepath => 'CellularRule190', coordinate_type => 'Product' ],
[0,undef, planepath => 'CellularRule190', coordinate_type => 'Radius' ],
[0,undef, planepath => 'CellularRule190', coordinate_type => 'RSquared' ],
[undef,undef, planepath => 'UlamWarburton', coordinate_type => 'X' ],
[undef,undef, planepath => 'UlamWarburton', coordinate_type => 'Y' ],
[undef,undef, planepath => 'UlamWarburton', coordinate_type => 'Sum' ],
[undef,undef, planepath => 'UlamWarburton', coordinate_type => 'Product' ],
[0,undef, planepath => 'UlamWarburton', coordinate_type => 'Radius' ],
[0,undef, planepath => 'UlamWarburton', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'X' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'Y' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'Sum' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'Product' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'Radius' ],
[0,undef, planepath => 'UlamWarburtonQuarter', coordinate_type => 'RSquared' ],
[3,undef, planepath => 'PythagoreanTree', coordinate_type => 'X' ],
[4,undef, planepath => 'PythagoreanTree', coordinate_type => 'Y' ],
[7,undef, planepath => 'PythagoreanTree', coordinate_type => 'Sum' ],
[3*4,undef, planepath => 'PythagoreanTree', coordinate_type => 'Product' ],
[5,undef, planepath => 'PythagoreanTree', coordinate_type => 'Radius' ],
[25,undef, planepath => 'PythagoreanTree', coordinate_type => 'RSquared' ],
[undef,undef, planepath => 'PythagoreanTree', coordinate_type => 'DiffXY' ],
[undef,undef, planepath => 'PythagoreanTree', coordinate_type => 'DiffYX' ],
[1,undef, planepath => 'PythagoreanTree', coordinate_type => 'AbsDiff' ],
[2,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'X' ],
[1,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'Y' ],
[3,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'Sum' ],
[2,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'Product' ],
#[sqrt(5),undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'Radius' ],
[5,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'RSquared' ],
[1,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'DiffXY' ],
[undef,-1, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'DiffYX' ],
[1,undef, planepath => 'PythagoreanTree,coordinates=PQ', coordinate_type => 'AbsDiff' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'X' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'Y' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'Sum' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'Product' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'Radius' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'DiffXY' ],
[undef,0, planepath => 'HypotOctant', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'HypotOctant', coordinate_type => 'AbsDiff' ],
[2,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'X' ],
[1,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'Y' ],
[3,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'Sum' ],
[2,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'Product' ],
# [sqrt(5),undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'Radius' ],
[5,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'RSquared' ],
[1,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'DiffXY' ],
[undef,-1, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'DiffYX' ],
[1,undef, planepath => 'DivisibleColumns,divisor_type=proper', coordinate_type => 'AbsDiff' ],
[1,undef, planepath => 'DivisibleColumns', coordinate_type => 'X' ],
[1,undef, planepath => 'DivisibleColumns', coordinate_type => 'Y' ],
[2,undef, planepath => 'DivisibleColumns', coordinate_type => 'Sum' ],
[1,undef, planepath => 'DivisibleColumns', coordinate_type => 'Product' ],
# [sqrt(2),undef, planepath => 'DivisibleColumns', coordinate_type => 'Radius' ],
[2,undef, planepath => 'DivisibleColumns', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'DivisibleColumns', coordinate_type => 'DiffXY' ],
[undef,0, planepath => 'DivisibleColumns', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'DivisibleColumns', coordinate_type => 'AbsDiff' ],
[1,undef, planepath => 'CoprimeColumns', coordinate_type => 'X' ],
[1,undef, planepath => 'CoprimeColumns', coordinate_type => 'Y' ],
[2,undef, planepath => 'CoprimeColumns', coordinate_type => 'Sum' ],
[1,undef, planepath => 'CoprimeColumns', coordinate_type => 'Product' ],
# [sqrt(2),undef, planepath => 'CoprimeColumns', coordinate_type => 'Radius' ],
[2,undef, planepath => 'CoprimeColumns', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'CoprimeColumns', coordinate_type => 'DiffXY' ],
[undef,0, planepath => 'CoprimeColumns', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'CoprimeColumns', coordinate_type => 'AbsDiff' ],
[1,undef, planepath => 'RationalsTree', coordinate_type => 'X' ],
[1,undef, planepath => 'RationalsTree', coordinate_type => 'Y' ],
# X>=1 and Y>=1 always so Sum>=2
[2,undef, planepath => 'RationalsTree', coordinate_type => 'Sum' ],
[1,undef, planepath => 'RationalsTree', coordinate_type => 'Product' ],
# [sqrt(2),undef, planepath => 'RationalsTree', coordinate_type => 'Radius' ],
[2,undef, planepath => 'RationalsTree', coordinate_type => 'RSquared' ],
# whole first quadrant so diff positive and negative
[undef,undef, planepath => 'RationalsTree', coordinate_type => 'DiffXY' ],
[undef,undef, planepath => 'RationalsTree', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'RationalsTree', coordinate_type => 'AbsDiff' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'X' ],
[undef,undef, planepath => 'QuadricCurve', coordinate_type => 'Y' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'Sum' ],
[undef,undef, planepath => 'QuadricCurve', coordinate_type => 'Product' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'Radius' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'RSquared' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'DiffXY' ],
[undef,0, planepath => 'QuadricCurve', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'QuadricCurve', coordinate_type => 'AbsDiff' ],
[0,5, planepath => 'Rows,width=6', coordinate_type => 'X' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'Y' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'Sum' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'Product' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'Radius' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'RSquared' ],
[undef,5, planepath => 'Rows,width=6', coordinate_type => 'DiffXY' ],
[-5,undef, planepath => 'Rows,width=6', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'Rows,width=6', coordinate_type => 'AbsDiff' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'X' ],
[0,5, planepath => 'Columns,height=6', coordinate_type => 'Y' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'Sum' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'Product' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'Radius' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'RSquared' ],
[-5,undef, planepath => 'Columns,height=6', coordinate_type => 'DiffXY' ],
[undef,5, planepath => 'Columns,height=6', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'Columns,height=6', coordinate_type => 'AbsDiff' ],
# step=0 vertical on Y axis only
[0,0, planepath=>'PyramidRows,step=0', coordinate_type => 'X' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'Y' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'Sum' ],
[0,0, planepath=>'PyramidRows,step=0', coordinate_type => 'Product' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'Radius' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'RSquared' ],
[undef,0, planepath=>'PyramidRows,step=0', coordinate_type => 'DiffXY' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'DiffYX' ],
[0,undef, planepath=>'PyramidRows,step=0', coordinate_type => 'AbsDiff' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'X' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'Y' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'Sum' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'Product' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'Radius' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'RSquared' ],
[undef,0, planepath=>'PyramidRows,step=1', coordinate_type => 'DiffXY' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'DiffYX' ],
[0,undef, planepath=>'PyramidRows,step=1', coordinate_type => 'AbsDiff' ],
[undef,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'X' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'Y' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'Sum' ],
[undef,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'Product' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'Radius' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'RSquared'],
[undef,0, planepath=>'PyramidRows,step=2', coordinate_type=>'DiffXY' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'DiffYX' ],
[0,undef, planepath=>'PyramidRows,step=2', coordinate_type=>'AbsDiff' ],
[undef,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'X' ],
[0,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'Y' ],
[0,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'Sum' ],
[undef,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'Product' ],
[0,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'Radius' ],
[0,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'RSquared' ],
[undef,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'DiffXY' ],
[undef,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'PyramidRows,step=3', coordinate_type => 'AbsDiff' ],
# Y <= X-1, so X-Y >= 1
# Y-X <= -1
[1,undef, planepath => 'SierpinskiCurve', coordinate_type => 'DiffXY' ],
[undef,-1, planepath => 'SierpinskiCurve', coordinate_type => 'DiffYX' ],
[1,undef, planepath => 'SierpinskiCurve', coordinate_type => 'AbsDiff' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'X' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'Y' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'Sum' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'Product' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'Radius' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'RSquared' ],
[undef,0, planepath => 'HIndexing', coordinate_type => 'DiffXY' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'DiffYX' ],
[0,undef, planepath => 'HIndexing', coordinate_type => 'AbsDiff' ],
# right line
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'X' ],
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'Y' ],
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'Sum' ],
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'Product' ],
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'Radius' ],
[0,undef, planepath=>'CellularRule,rule=16', coordinate_type=>'RSquared' ],
[0,0, planepath=>'CellularRule,rule=16', coordinate_type=>'DiffXY' ],
[0,0, planepath=>'CellularRule,rule=16', coordinate_type=>'DiffYX' ],
[0,0, planepath=>'CellularRule,rule=16', coordinate_type=>'AbsDiff' ],
# centre line Y axis only
[0,0, planepath=>'CellularRule,rule=4', coordinate_type => 'X' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'Y' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'Sum' ],
[0,0, planepath=>'CellularRule,rule=4', coordinate_type => 'Product' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'Radius' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'RSquared' ],
[undef,0, planepath=>'CellularRule,rule=4', coordinate_type => 'DiffXY' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'DiffYX' ],
[0,undef, planepath=>'CellularRule,rule=4', coordinate_type => 'AbsDiff' ],
# left line
[undef,0, planepath=>'CellularRule,rule=2', coordinate_type=>'X' ],
[0,undef, planepath=>'CellularRule,rule=2', coordinate_type=>'Y' ],
[0,0, planepath=>'CellularRule,rule=2', coordinate_type=>'Sum' ],
[undef,0, planepath=>'CellularRule,rule=2', coordinate_type=>'Product' ],
[0,undef, planepath=>'CellularRule,rule=2', coordinate_type=>'Radius' ],
[0,undef, planepath=>'CellularRule,rule=2', coordinate_type=>'RSquared' ],
[undef,0, planepath=>'CellularRule,rule=2', coordinate_type=>'DiffXY' ],
[0,undef, planepath=>'CellularRule,rule=2', coordinate_type=>'DiffYX' ],
[0,undef, planepath=>'CellularRule,rule=2', coordinate_type=>'AbsDiff' ],
# left solid
[undef,0, planepath=>'CellularRule,rule=206', coordinate_type=>'X' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'Y' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'Sum' ],
[undef,0, planepath=>'CellularRule,rule=206', coordinate_type=>'Product' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'Radius' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'RSquared' ],
[undef,0, planepath=>'CellularRule,rule=206', coordinate_type=>'DiffXY' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'DiffYX' ],
[0,undef, planepath=>'CellularRule,rule=206', coordinate_type=>'AbsDiff' ],
# odd solid
[undef,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'X' ],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'Y' ],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'Sum' ],
[undef,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'Product'],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'Radius' ],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'RSquared'],
[undef,0, planepath=>'CellularRule,rule=50',coordinate_type=>'DiffXY' ],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'DiffYX' ],
[0,undef, planepath=>'CellularRule,rule=50',coordinate_type=>'AbsDiff' ],
) {
my ($want_min,$want_max, @parameters) = @$elem;
### @parameters
### $want_min
### $want_max
my $seq = Math::NumSeq::PlanePathCoord->new (@parameters);
ok ($seq->values_min, $want_min,
"values_min() ".join(',',@parameters));
ok ($seq->values_max, $want_max,
"values_max() ".join(',',@parameters));
}
#------------------------------------------------------------------------------
# values_min(), values_max() by running values
my @modules = (
# 'FourReplicate',
# module list begin
'KochCurve',
'KochPeaks',
'ChanTree,k=2',
'ChanTree',
'ChanTree,k=4',
'ChanTree,k=5',
'ChanTree,k=6',
'ChanTree,k=7',
'ChanTree,k=2,n_start=1',
'ChanTree,n_start=1',
'ChanTree,k=4,n_start=1',
'ChanTree,k=5,n_start=1',
'CoprimeColumns',
'DivisibleColumns',
'DivisibleColumns,divisor_type=proper',
'FractionsTree',
'GreekKeySpiral',
'GreekKeySpiral,turns=0',
'GreekKeySpiral,turns=1',
'GreekKeySpiral,turns=3',
'GreekKeySpiral,turns=4',
'GreekKeySpiral,turns=5',
'GreekKeySpiral,turns=6',
'GreekKeySpiral,turns=7',
'GreekKeySpiral,turns=8',
'GreekKeySpiral,turns=37',
'SierpinskiTriangle',
'SierpinskiTriangle,align=right',
'SierpinskiTriangle,align=left',
'SierpinskiTriangle,align=diagonal',
'SierpinskiTriangle,n_start=37',
'SierpinskiTriangle,n_start=37,align=right',
'SierpinskiTriangle,n_start=37,align=left',
'SierpinskiTriangle,n_start=37,align=diagonal',
'KochSnowflakes',
'KochSquareflakes',
'KochSquareflakes,inward=>1',
'SquareSpiral',
'SquareSpiral,wider=1',
'SquareSpiral,wider=2',
'SquareSpiral,wider=3',
'SquareSpiral,wider=4',
'SquareSpiral,wider=5',
'SquareSpiral,wider=6',
'SquareSpiral,wider=37',
'SquareSpiral,n_start=37',
'SquareSpiral,n_start=37,wider=1',
'SquareSpiral,n_start=37,wider=2',
'SquareSpiral,n_start=37,wider=3',
'SquareSpiral,n_start=37,wider=4',
'SquareSpiral,n_start=37,wider=5',
'SquareSpiral,n_start=37,wider=6',
'SquareSpiral,n_start=37,wider=37',
'CellularRule,rule=6', # left 1,2 line
'CellularRule,rule=6,n_start=0',
'CellularRule,rule=6,n_start=37',
'CellularRule,rule=20', # right 1,2 line
'CellularRule,rule=20,n_start=0',
'CellularRule,rule=20,n_start=37',
'CellularRule,rule=14', # left 2 cell line
'CellularRule,rule=14,n_start=0',
'CellularRule,rule=14,n_start=37',
'CellularRule,rule=84', # right 2 cell line
'CellularRule,rule=84,n_start=0',
'CellularRule,rule=84,n_start=37',
'AztecDiamondRings',
'DiamondArms',
'SquareArms',
'HexArms',
'*ToothpickUpist',
'Hypot',
'Hypot,points=even',
'Hypot,points=odd',
'HypotOctant',
'HypotOctant,points=even',
'HypotOctant,points=odd',
'TriangularHypot',
'TriangularHypot,points=odd',
'TriangularHypot,points=all',
'TriangularHypot,points=hex',
'TriangularHypot,points=hex_rotated',
'TriangularHypot,points=hex_centred',
'PyramidRows',
'PyramidRows,step=0',
'PyramidRows,step=1',
'PyramidRows,step=3',
'PyramidRows,step=4',
'PyramidRows,step=5',
'PyramidRows,step=6',
'PyramidRows,step=7',
'PyramidRows,step=37',
'PyramidRows,align=right',
'PyramidRows,align=right,step=0',
'PyramidRows,align=right,step=1',
'PyramidRows,align=right,step=3',
'PyramidRows,align=right,step=4',
'PyramidRows,align=right,step=5',
'PyramidRows,align=right,step=6',
'PyramidRows,align=right,step=7',
'PyramidRows,align=right,step=37',
'PyramidRows,align=left',
'PyramidRows,align=left,step=0',
'PyramidRows,align=left,step=1',
'PyramidRows,align=left,step=3',
'PyramidRows,align=left,step=4',
'PyramidRows,align=left,step=5',
'PyramidRows,align=left,step=6',
'PyramidRows,align=left,step=7',
'PyramidRows,align=left,step=37',
'*HTree',
'PythagoreanTree,tree_type=UMT',
'PythagoreanTree,tree_type=UMT,coordinates=AC',
'PythagoreanTree,tree_type=UMT,coordinates=BC',
'PythagoreanTree,tree_type=UMT,coordinates=PQ',
'PythagoreanTree,tree_type=UMT,coordinates=SM',
'PythagoreanTree,tree_type=UMT,coordinates=SC',
'PythagoreanTree,tree_type=UMT,coordinates=MC',
'PythagoreanTree',
'PythagoreanTree,coordinates=AC',
'PythagoreanTree,coordinates=BC',
'PythagoreanTree,coordinates=PQ',
'PythagoreanTree,coordinates=SM',
'PythagoreanTree,coordinates=SC',
'PythagoreanTree,coordinates=MC',
'PythagoreanTree,tree_type=FB',
'PythagoreanTree,tree_type=FB,coordinates=AC',
'PythagoreanTree,tree_type=FB,coordinates=BC',
'PythagoreanTree,tree_type=FB,coordinates=PQ',
'PythagoreanTree,tree_type=FB,coordinates=SM',
'PythagoreanTree,tree_type=FB,coordinates=SC',
'PythagoreanTree,tree_type=FB,coordinates=MC',
'Rows,width=1',
'Rows,width=2',
'Rows,width=6',
'Rows,width=15',
'Rows',
'Columns,height=1',
'Columns,height=2',
'Columns,height=6',
'Columns,height=15',
'Columns',
'VogelFloret',
'VogelFloret,rotation_type=sqrt2',
'VogelFloret,rotation_type=sqrt3',
'VogelFloret,rotation_type=sqrt5',
'SacksSpiral',
'TheodorusSpiral',
'ArchimedeanChords',
'HexSpiral',
'HexSpiral,wider=1',
'HexSpiral,wider=2',
'HexSpiral,wider=3',
'HexSpiral,wider=4',
'HexSpiral,wider=5',
'HexSpiral,wider=37',
'HexSpiralSkewed',
'HexSpiralSkewed,wider=1',
'HexSpiralSkewed,wider=2',
'HexSpiralSkewed,wider=3',
'HexSpiralSkewed,wider=4',
'HexSpiralSkewed,wider=5',
'HexSpiralSkewed,wider=37',
'DragonCurve',
'DragonCurve,arms=2',
'DragonCurve,arms=3',
'DragonCurve,arms=4',
'DragonRounded',
'DragonRounded,arms=2',
'DragonRounded,arms=3',
'DragonRounded,arms=4',
'DragonMidpoint',
'DragonMidpoint,arms=2',
'DragonMidpoint,arms=3',
'DragonMidpoint,arms=4',
'R5DragonCurve',
'R5DragonCurve,arms=2',
'R5DragonCurve,arms=3',
'R5DragonCurve,arms=4',
'R5DragonMidpoint',
'R5DragonMidpoint,arms=2',
'R5DragonMidpoint,arms=3',
'R5DragonMidpoint,arms=4',
'TerdragonCurve',
'TerdragonCurve,arms=2',
'TerdragonCurve,arms=3',
'TerdragonCurve,arms=4',
'TerdragonCurve,arms=5',
'TerdragonCurve,arms=6',
'TerdragonRounded',
'TerdragonRounded,arms=2',
'TerdragonRounded,arms=3',
'TerdragonRounded,arms=4',
'TerdragonRounded,arms=5',
'TerdragonRounded,arms=6',
'TerdragonMidpoint',
'TerdragonMidpoint,arms=2',
'TerdragonMidpoint,arms=3',
'TerdragonMidpoint,arms=4',
'TerdragonMidpoint,arms=5',
'TerdragonMidpoint,arms=6',
'FlowsnakeCentres',
'FlowsnakeCentres,arms=2',
'FlowsnakeCentres,arms=3',
'Flowsnake',
'Flowsnake,arms=2',
'Flowsnake,arms=3',
'PyramidSides',
'CornerReplicate',
'LTiling',
'LTiling,L_fill=left',
'LTiling,L_fill=upper',
'LTiling,L_fill=ends',
'LTiling,L_fill=all',
'ImaginaryBase',
'ImaginaryBase,radix=3',
'ImaginaryBase,radix=4',
'ImaginaryBase,radix=5',
'ImaginaryBase,radix=6',
'ImaginaryBase,radix=37',
'ImaginaryHalf',
'ImaginaryHalf,digit_order=XXY',
'ImaginaryHalf,digit_order=YXX',
'ImaginaryHalf,digit_order=XnXY',
'ImaginaryHalf,digit_order=XnYX',
'ImaginaryHalf,digit_order=YXnX',
'ImaginaryHalf,digit_order=XXY,radix=3',
'ImaginaryHalf,radix=37',
'ImaginaryHalf,radix=3',
'ImaginaryHalf,radix=4',
'ImaginaryHalf,radix=5',
'ImaginaryHalf,radix=6',
'FactorRationals',
'FactorRationals,sign_encoding=odd/even',
'FactorRationals,sign_encoding=negabinary',
'FactorRationals,sign_encoding=revbinary',
'FactorRationals,sign_encoding=spread',
'PowerArray',
'PowerArray,radix=3',
'PowerArray,radix=4',
'WythoffArray',
'WythoffArray,x_start=1',
'WythoffArray,y_start=1',
'WythoffArray,x_start=1,y_start=1',
'WythoffArray,x_start=5,y_start=7',
'*ToothpickTree',
'*ToothpickTree,parts=1',
'*ToothpickTree,parts=2',
'*ToothpickTree,parts=3',
'*ToothpickTree,parts=octant',
'*ToothpickTree,parts=octant_up',
'*ToothpickTree,parts=wedge',
'*ToothpickReplicate',
'*ToothpickReplicate,parts=1',
'*ToothpickReplicate,parts=2',
'*ToothpickReplicate,parts=3',
'*LCornerReplicate',
'*LCornerTree',
'*LCornerTree,parts=3',
'*LCornerTree,parts=2',
'*LCornerTree,parts=1',
'*LCornerTree,parts=octant',
'*LCornerTree,parts=octant+1',
'*LCornerTree,parts=octant_up',
'*LCornerTree,parts=octant_up+1',
'*LCornerTree,parts=wedge',
'*LCornerTree,parts=wedge+1',
'*LCornerTree,parts=diagonal-1',
'*LCornerTree,parts=diagonal',
'ZOrderCurve',
'ZOrderCurve,radix=3',
'ZOrderCurve,radix=9',
'ZOrderCurve,radix=37',
'DiagonalRationals',
'DiagonalRationals,direction=up',
'SierpinskiArrowhead',
'SierpinskiArrowhead,align=right',
'SierpinskiArrowhead,align=left',
'SierpinskiArrowhead,align=diagonal',
'SierpinskiArrowheadCentres',
'SierpinskiArrowheadCentres,align=right',
'SierpinskiArrowheadCentres,align=left',
'SierpinskiArrowheadCentres,align=diagonal',
'PentSpiral',
'PentSpiral,n_start=0',
'PentSpiral,n_start=37',
'PentSpiralSkewed',
'PentSpiralSkewed,n_start=0',
'PentSpiralSkewed,n_start=37',
'HeptSpiralSkewed',
'HeptSpiralSkewed,n_start=0',
'HeptSpiralSkewed,n_start=37',
'*OneOfEight,parts=wedge',
'*OneOfEight,parts=octant_up',
'*OneOfEight',
'*OneOfEight,parts=4',
'*OneOfEight,parts=1',
'*OneOfEight,parts=octant',
'*OneOfEight,parts=3mid',
'*OneOfEight,parts=3side',
'*ToothpickSpiral',
'*ToothpickSpiral,n_start=0',
'*ToothpickSpiral,n_start=37',
'Staircase',
'Staircase,n_start=0',
'Staircase,n_start=37',
'StaircaseAlternating',
'StaircaseAlternating,n_start=0',
'StaircaseAlternating,n_start=37',
'StaircaseAlternating,end_type=square',
'StaircaseAlternating,end_type=square,n_start=0',
'StaircaseAlternating,end_type=square,n_start=37',
'OctagramSpiral',
'OctagramSpiral,n_start=0',
'OctagramSpiral,n_start=37',
'ComplexPlus',
'ComplexPlus,realpart=2',
'ComplexPlus,realpart=3',
'ComplexPlus,realpart=4',
'ComplexPlus,realpart=5',
'MPeaks',
'PyramidSpiral',
'PyramidSpiral,n_start=0',
'PyramidSpiral,n_start=37',
'GrayCode,apply_type=TsF',
'GrayCode,apply_type=FsT',
'GrayCode,apply_type=Ts',
'GrayCode,apply_type=Fs',
'GrayCode,apply_type=sT',
'GrayCode,apply_type=sF',
'GrayCode,radix=3,apply_type=TsF',
'GrayCode,radix=3,apply_type=FsT',
'GrayCode,radix=3,apply_type=Ts',
'GrayCode,radix=3,apply_type=Fs',
'GrayCode,radix=3,apply_type=sT',
'GrayCode,radix=3,apply_type=sF',
'GrayCode,radix=3,gray_type=modular,apply_type=TsF',
'GrayCode,radix=3,gray_type=modular,apply_type=Ts',
'GrayCode,radix=3,gray_type=modular,apply_type=Fs',
'GrayCode,radix=3,gray_type=modular,apply_type=FsT',
'GrayCode,radix=3,gray_type=modular,apply_type=sT',
'GrayCode,radix=3,gray_type=modular,apply_type=sF',
'GrayCode,radix=4,apply_type=TsF',
'GrayCode,radix=4,apply_type=FsT',
'GrayCode,radix=4,apply_type=Ts',
'GrayCode,radix=4,apply_type=Fs',
'GrayCode,radix=4,apply_type=sT',
'GrayCode,radix=4,apply_type=sF',
'GrayCode,radix=4,gray_type=modular,apply_type=TsF',
'GrayCode,radix=4,gray_type=modular,apply_type=Ts',
'GrayCode,radix=4,gray_type=modular,apply_type=Fs',
'GrayCode,radix=4,gray_type=modular,apply_type=FsT',
'GrayCode,radix=4,gray_type=modular,apply_type=sT',
'GrayCode,radix=4,gray_type=modular,apply_type=sF',
'GrayCode,radix=5,apply_type=TsF',
'GrayCode,radix=5,apply_type=FsT',
'GrayCode,radix=5,apply_type=Ts',
'GrayCode,radix=5,apply_type=Fs',
'GrayCode,radix=5,apply_type=sT',
'GrayCode,radix=5,apply_type=sF',
'GrayCode,radix=5,gray_type=modular,apply_type=TsF',
'GrayCode,radix=5,gray_type=modular,apply_type=Ts',
'GrayCode,radix=5,gray_type=modular,apply_type=Fs',
'GrayCode,radix=5,gray_type=modular,apply_type=FsT',
'GrayCode,radix=5,gray_type=modular,apply_type=sT',
'GrayCode,radix=5,gray_type=modular,apply_type=sF',
'GrayCode,radix=6,apply_type=TsF',
'GrayCode,radix=6,apply_type=FsT',
'GrayCode,radix=6,apply_type=Ts',
'GrayCode,radix=6,apply_type=Fs',
'GrayCode,radix=6,apply_type=sT',
'GrayCode,radix=6,apply_type=sF',
'GrayCode,radix=6,gray_type=modular,apply_type=TsF',
'GrayCode,radix=6,gray_type=modular,apply_type=Ts',
'GrayCode,radix=6,gray_type=modular,apply_type=Fs',
'GrayCode,radix=6,gray_type=modular,apply_type=FsT',
'GrayCode,radix=6,gray_type=modular,apply_type=sT',
'GrayCode,radix=6,gray_type=modular,apply_type=sF',
'CellularRule',
'CellularRule,rule=0', # single cell
'CellularRule,rule=8', # single cell
'CellularRule,rule=32', # single cell
'CellularRule,rule=40', # single cell
'CellularRule,rule=64', # single cell
'CellularRule,rule=72', # single cell
'CellularRule,rule=96', # single cell
'CellularRule,rule=104', # single cell
'CellularRule,rule=128', # single cell
'CellularRule,rule=136', # single cell
'CellularRule,rule=160', # single cell
'CellularRule,rule=168', # single cell
'CellularRule,rule=192', # single cell
'CellularRule,rule=200', # single cell
'CellularRule,rule=224', # single cell
'CellularRule,rule=232', # single cell
'CellularRule,rule=50', # solid every second cell
'CellularRule,rule=50,n_start=0',
'CellularRule,rule=50,n_start=37',
'CellularRule,rule=58', # solid every second cell
'CellularRule54',
'CellularRule54,n_start=0',
'CellularRule54,n_start=37',
'CellularRule57',
'CellularRule57,n_start=0',
'CellularRule57,n_start=37',
'CellularRule57,mirror=1',
'CellularRule190,n_start=0',
'CellularRule190',
'CellularRule190',
'CellularRule190,mirror=1',
'CellularRule190,mirror=1,n_start=0',
'CellularRule,rule=16', # right line
'CellularRule,rule=16,n_start=0',
'CellularRule,rule=16,n_start=37',
'CellularRule,rule=24', # right line
'CellularRule,rule=48', # right line
'CellularRule,rule=2', # left line
'CellularRule,rule=2,n_start=0',
'CellularRule,rule=2,n_start=37',
'CellularRule,rule=10', # left line
'CellularRule,rule=34', # left line
'CellularRule,rule=4', # centre line
'CellularRule,rule=4,n_start=0',
'CellularRule,rule=4,n_start=37',
'CellularRule,rule=12', # centre line
'CellularRule,rule=36', # centre line
'CellularRule,rule=206', # left solid
'CellularRule,rule=206,n_start=0',
'CellularRule,rule=206,n_start=37',
'CellularRule,rule=18', # Sierpinski
'CellularRule,rule=18,n_start=0',
'CellularRule,rule=18,n_start=37',
'CellularRule,rule=60',
'CellularRule,rule=18,n_start=0',
'CellularRule,rule=18,n_start=37',
'CellularRule,rule=220', # right half solid
'CellularRule,rule=220,n_start=0',
'CellularRule,rule=220,n_start=37',
'CellularRule,rule=222', # solid
'AlternatePaper',
'AlternatePaper,arms=2',
'AlternatePaper,arms=3',
'AlternatePaper,arms=4',
'AlternatePaper,arms=5',
'AlternatePaper,arms=6',
'AlternatePaper,arms=7',
'AlternatePaper,arms=8',
'AlternatePaperMidpoint',
'AlternatePaperMidpoint,arms=2',
'AlternatePaperMidpoint,arms=3',
'AlternatePaperMidpoint,arms=4',
'AlternatePaperMidpoint,arms=5',
'AlternatePaperMidpoint,arms=6',
'AlternatePaperMidpoint,arms=7',
'AlternatePaperMidpoint,arms=8',
'GosperReplicate',
'GosperSide',
'GosperIslands',
'UlamWarburton',
'UlamWarburton,parts=2',
'UlamWarburton,parts=1',
'UlamWarburtonQuarter',
'CubicBase',
'PeanoCurve',
'PeanoCurve,radix=2',
'PeanoCurve,radix=4',
'PeanoCurve,radix=5',
'PeanoCurve,radix=17',
'KnightSpiral',
'DiagonalsAlternating',
'GcdRationals',
'GcdRationals,pairs_order=rows_reverse',
'GcdRationals,pairs_order=diagonals_down',
'GcdRationals,pairs_order=diagonals_up',
'CCurve',
'ComplexMinus',
'ComplexMinus,realpart=2',
'ComplexMinus,realpart=3',
'ComplexMinus,realpart=4',
'ComplexMinus,realpart=5',
'ComplexRevolving',
'SierpinskiCurve',
'SierpinskiCurve,arms=2',
'SierpinskiCurve,arms=3',
'SierpinskiCurve,diagonal_spacing=5',
'SierpinskiCurve,straight_spacing=5',
'SierpinskiCurve,diagonal_spacing=3,straight_spacing=7',
'SierpinskiCurve,diagonal_spacing=3,straight_spacing=7,arms=7',
'SierpinskiCurve,arms=4',
'SierpinskiCurve,arms=5',
'SierpinskiCurve,arms=6',
'SierpinskiCurve,arms=7',
'SierpinskiCurve,arms=8',
'TriangleSpiralSkewed',
'TriangleSpiralSkewed,n_start=37',
'TriangleSpiralSkewed,skew=right',
'TriangleSpiralSkewed,skew=right,n_start=37',
'TriangleSpiralSkewed,skew=up',
'TriangleSpiralSkewed,skew=up,n_start=37',
'TriangleSpiralSkewed,skew=down',
'TriangleSpiralSkewed,skew=down,n_start=37',
'DiagonalsOctant',
'DiagonalsOctant,direction=up',
'HIndexing',
'SierpinskiCurveStair',
'SierpinskiCurveStair,diagonal_length=2',
'SierpinskiCurveStair,diagonal_length=3',
'SierpinskiCurveStair,diagonal_length=4',
'SierpinskiCurveStair,arms=2',
'SierpinskiCurveStair,arms=3,diagonal_length=2',
'SierpinskiCurveStair,arms=4',
'SierpinskiCurveStair,arms=5',
'SierpinskiCurveStair,arms=6,diagonal_length=5',
'SierpinskiCurveStair,arms=7',
'SierpinskiCurveStair,arms=8',
'QuadricCurve',
'QuadricIslands',
'CfracDigits,radix=1',
'CfracDigits',
'CfracDigits,radix=3',
'CfracDigits,radix=4',
'CfracDigits,radix=37',
'RationalsTree,tree_type=L',
'RationalsTree,tree_type=HCS',
'RationalsTree',
'RationalsTree,tree_type=CW',
'RationalsTree,tree_type=AYT',
'RationalsTree,tree_type=Bird',
'RationalsTree,tree_type=Drib',
'DekkingCurve',
'DekkingCentres',
'WunderlichSerpentine,radix=2',
'WunderlichSerpentine',
'WunderlichSerpentine,serpentine_type=100_000_000',
'WunderlichSerpentine,serpentine_type=000_000_001',
'WunderlichSerpentine,radix=4',
'WunderlichSerpentine,radix=5,serpentine_type=coil',
'DigitGroups',
'DigitGroups,radix=3',
'DigitGroups,radix=4',
'DigitGroups,radix=5',
'DigitGroups,radix=37',
'QuintetReplicate',
'QuintetCurve',
'QuintetCurve,arms=2',
'QuintetCurve,arms=3',
'QuintetCurve,arms=4',
'QuintetCentres',
'QuintetCentres,arms=2',
'QuintetCentres,arms=3',
'QuintetCentres,arms=4',
'TriangleSpiral',
'TriangleSpiral,n_start=37',
# 'File',
'PixelRings',
'FilledRings',
'CretanLabyrinth',
'AnvilSpiral',
'AnvilSpiral,wider=1',
'AnvilSpiral,wider=2',
'AnvilSpiral,wider=9',
'AnvilSpiral,wider=17',
'AR2W2Curve',
'AR2W2Curve,start_shape=D2',
'AR2W2Curve,start_shape=B2',
'AR2W2Curve,start_shape=B1rev',
'AR2W2Curve,start_shape=D1rev',
'AR2W2Curve,start_shape=A2rev',
'BetaOmega',
'KochelCurve',
'CincoCurve',
'HilbertSpiral',
'HilbertCurve',
'WunderlichMeander',
'FibonacciWordFractal',
'DiamondSpiral',
'SquareReplicate',
'Diagonals',
'Diagonals,direction=up',
#
'Diagonals,x_start=1',
'Diagonals,y_start=1',
'Diagonals,x_start=1,direction=up',
'Diagonals,y_start=1,direction=up',
#
'Diagonals,x_start=-1',
'Diagonals,y_start=-1',
'Diagonals,x_start=-1,direction=up',
'Diagonals,y_start=-1,direction=up',
#
'Diagonals,x_start=2',
'Diagonals,y_start=2',
'Diagonals,x_start=2,direction=up',
'Diagonals,y_start=2,direction=up',
#
'Diagonals,x_start=-2',
'Diagonals,y_start=-2',
'Diagonals,x_start=-2,direction=up',
'Diagonals,y_start=-2,direction=up',
#
'Diagonals,x_start=6',
'Diagonals,y_start=6',
'Diagonals,x_start=6,direction=up',
'Diagonals,y_start=6,direction=up',
#
'Diagonals,x_start=-6',
'Diagonals,y_start=-6',
'Diagonals,x_start=-6,direction=up',
'Diagonals,y_start=-6,direction=up',
#
'Diagonals,x_start=3,y_start=6',
'Diagonals,x_start=-3,y_start=0',
'Diagonals,x_start=0,y_start=-6',
'Diagonals,x_start=5,y_start=-2',
'Diagonals,x_start=-5,y_start=2',
'Diagonals,x_start=-5,y_start=2',
'Diagonals,x_start=-5,y_start=-2',
'Diagonals,x_start=3,y_start=-5',
'Diagonals,x_start=-3,y_start=5',
'Diagonals,x_start=-3,y_start=5',
'Diagonals,x_start=-3,y_start=-5',
#
'Diagonals,x_start=3,y_start=6,direction=up',
'Diagonals,x_start=-3,y_start=0,direction=up',
'Diagonals,x_start=0,y_start=-6,direction=up',
'Diagonals,x_start=5,y_start=-2,direction=up',
'Diagonals,x_start=-5,y_start=2,direction=up',
'Diagonals,x_start=-5,y_start=2,direction=up',
'Diagonals,x_start=-5,y_start=-2,direction=up',
'Diagonals,x_start=3,y_start=-5,direction=up',
'Diagonals,x_start=-3,y_start=5,direction=up',
'Diagonals,x_start=-3,y_start=5,direction=up',
'Diagonals,x_start=-3,y_start=-5,direction=up',
# 'Diagonals,x_start=20,y_start=10',
# 'Diagonals,x_start=20,y_start=10
# 'Diagonals,x_start=3,y_start=6,direction=up',
# 'Diagonals,x_start=3,y_start=-6,direction=up',
# 'Diagonals,x_start=-3,y_start=6,direction=up',
# 'Diagonals,x_start=-3,y_start=-6,direction=up',
'MultipleRings,step=0',
'MultipleRings,ring_shape=polygon,step=0',
'MultipleRings,step=1',
'MultipleRings,ring_shape=polygon,step=1',
'MultipleRings,step=2',
'MultipleRings,ring_shape=polygon,step=2',
'MultipleRings,step=3',
'MultipleRings,step=5',
'MultipleRings,step=6',
'MultipleRings,step=7',
'MultipleRings,step=8',
'MultipleRings,step=37',
'MultipleRings,ring_shape=polygon,step=3',
'MultipleRings,ring_shape=polygon,step=4',
'MultipleRings,ring_shape=polygon,step=5',
'MultipleRings,ring_shape=polygon,step=6',
'MultipleRings,ring_shape=polygon,step=7',
'MultipleRings,ring_shape=polygon,step=8',
'MultipleRings,ring_shape=polygon,step=9',
'MultipleRings,ring_shape=polygon,step=10',
'MultipleRings,ring_shape=polygon,step=11',
'MultipleRings,ring_shape=polygon,step=12',
'MultipleRings,ring_shape=polygon,step=13',
'MultipleRings,ring_shape=polygon,step=14',
'MultipleRings,ring_shape=polygon,step=15',
'MultipleRings,ring_shape=polygon,step=16',
'MultipleRings,ring_shape=polygon,step=17',
'MultipleRings,ring_shape=polygon,step=18',
'MultipleRings,ring_shape=polygon,step=37',
'Corner',
'Corner,wider=1',
'Corner,wider=2',
'Corner,wider=5',
'Corner,wider=37',
# module list end
# cellular 0 to 255
(map {("CellularRule,rule=$_",
"CellularRule,rule=$_,n_start=0",
"CellularRule,rule=$_,n_start=37")} 0..255),
);
foreach (@modules) { s/^\*// }
{
require Math::NumSeq::PlanePathDelta;
require Math::NumSeq::PlanePathTurn;
require Math::NumSeq::PlanePathN;
foreach my $mod (@modules) {
next unless want_planepath($mod);
my $bad = 0;
foreach my $elem (
['Math::NumSeq::PlanePathDelta','delta_type'],
['Math::NumSeq::PlanePathCoord','coordinate_type'],
['Math::NumSeq::PlanePathTurn','turn_type'],
['Math::NumSeq::PlanePathN','line_type'],
) {
my ($class, $pname) = @$elem;
foreach my $param (@{$class->parameter_info_hash
->{$pname}->{'choices'}}) {
next unless want_coordinate($param);
MyTestHelpers::diag ("$mod $param");
### $mod
### $param
my $seq = $class->new (planepath => $mod,
$pname => $param);
my $planepath_object = $seq->{'planepath_object'};
### planepath_object: ref $planepath_object
my $i_start = $seq->i_start;
if (! defined $i_start) {
die "Oops, i_start=undef";
}
my $characteristic_integer = $seq->characteristic('integer') || 0;
my $saw_characteristic_integer = 1;
my $saw_characteristic_integer_at = '';
my $saw_values_min = 999999999;
my $saw_values_max = -999999999;
my $saw_values_min_at = 'sentinel';
my $saw_values_max_at = 'sentinel';
my $saw_increasing = 1;
my $saw_non_decreasing = 1;
my $saw_increasing_at = '[default]';
my $saw_non_decreasing_at = '[default]';
my $prev_value;
my $count = 0;
my $i_limit = 800;
if ($mod =~ /Vogel|Theod|Archim/
&& $param =~ /axis|[XY]_neg|diagonal/i) {
$i_limit = 20;
}
if ($mod =~ /Hypot|PixelRings|FilledRings/
&& $param =~ /axis|[XY]_neg|diagonal/i) {
$i_limit = 50;
}
if ($mod =~ /CellularRule/
&& $param =~ /axis|[XY]_neg|diagonal/i) {
$i_limit = 80;
}
my $i_end = $i_start + $i_limit;
### $i_limit
foreach my $i ($i_start .. $i_end) {
my $value = $seq->ith($i);
### $i
### $value
next if ! defined $value;
$count++;
if ($saw_characteristic_integer) {
if ($value != int($value)) {
$saw_characteristic_integer = 0;
$saw_characteristic_integer_at = "i=$i value=$value";
}
}
if ($value < $saw_values_min) {
$saw_values_min = $value;
if (my ($x,$y) = $seq->{'planepath_object'}->n_to_xy($i)) {
$saw_values_min_at = "i=$i xy=$x,$y";
} else {
$saw_values_min_at = "i=$i";
}
}
if ($value > $saw_values_max) {
$saw_values_max = $value;
$saw_values_max_at = "i=$i";
}
# ### $value
# ### $prev_value
if (defined $prev_value) {
if (abs($value - $prev_value) < 0.0000001) {
$prev_value = $value;
}
if ($value <= $prev_value
&& ! is_nan($prev_value)
&& ! ($value==pos_infinity() && $prev_value==pos_infinity())) {
# ### not increasing ...
if ($saw_increasing) {
$saw_increasing = 0;
$saw_increasing_at = "i=$i value=$value prev_value=$prev_value";
}
if ($value < $prev_value) {
if ($saw_non_decreasing) {
$saw_non_decreasing = 0;
$saw_non_decreasing_at = "i=$i";
}
}
}
}
$prev_value = $value;
}
### $count
next if $count == 0;
### $saw_values_min
### $saw_values_min_at
### $saw_values_max
### $saw_values_max_at
my $values_min = $seq->values_min;
my $values_max = $seq->values_max;
if (! defined $values_min) {
if ($saw_values_min >= -3 && $count >= 3) {
MyTestHelpers::diag ("$mod $param values_min=undef vs saw_values_min=$saw_values_min apparent lower bound at $saw_values_min_at");
}
$values_min = $saw_values_min;
}
if (! defined $values_max) {
if ($saw_values_max <= 3 && $count >= 3) {
MyTestHelpers::diag ("$mod $param values_max=undef vs saw_values_max=$saw_values_max apparent upper bound at $saw_values_max_at");
}
$values_max = $saw_values_max;
}
if (my $coderef = $planepath_object->can("_NumSeq_${param}_max_is_supremum")) {
if ($planepath_object->$coderef) {
if ($saw_values_max == $values_max) {
MyTestHelpers::diag ("$mod $param values_max=$values_max vs saw_values_max=$saw_values_max at $saw_values_max_at supposed to be supremum only");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
if ($saw_values_max < $values_max) {
$saw_values_max = $values_max;
$saw_values_max_at = 'supremum';
}
}
}
if (my $coderef = $planepath_object->can("_NumSeq_${param}_min_is_infimum")) {
if ($planepath_object->$coderef()) {
if ($saw_values_min == $values_min) {
MyTestHelpers::diag ("$mod $param values_min=$values_min vs saw_values_min=$saw_values_min at $saw_values_min_at supposed to be infimum only");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
}
if ($saw_values_min > $values_min) {
$saw_values_min = $values_min;
$saw_values_min_at = 'infimum';
}
}
}
# these come arbitrarily close to dX==dY, in general, probably
if (($mod eq 'MultipleRings,step=2'
|| $mod eq 'MultipleRings,step=3'
|| $mod eq 'MultipleRings,step=5'
|| $mod eq 'MultipleRings,step=7'
|| $mod eq 'MultipleRings,step=37'
)
&& $param eq 'AbsDiff'
&& $saw_values_min > 0 && $saw_values_min < 0.3) {
$saw_values_min = 0;
$saw_values_min_at = 'override';
}
# supremum +/- 1 without ever actually reaching
if (($mod eq 'MultipleRings'
)
&& ($param eq 'dX'
|| $param eq 'dY'
)) {
$saw_values_min = -1;
$saw_values_min_at = 'override';
}
# if (($mod eq 'MultipleRings,step=1'
# || $mod eq 'MultipleRings,step=2'
# || $mod eq 'MultipleRings,step=3'
# || $mod eq 'MultipleRings,step=4'
# || $mod eq 'MultipleRings,step=5'
# || $mod eq 'MultipleRings,step=6'
# || $mod eq 'MultipleRings'
# )
# && ($param eq 'dX'
# || $param eq 'dY'
# || $param eq 'Dist'
# )) {
# my ($step) = ($mod =~ /MultipleRings,step=(\d+)/);
# $step ||= 6;
# if (-$saw_values_min > 2*PI()/$step*0.85
# && -$saw_values_min < 2*PI()/$step) {
# $saw_values_min = -2*PI() / $step;
# $saw_values_min_at = 'override';
# }
# if ($saw_values_max > 2*PI()/$step*0.85
# && $saw_values_max < 2*PI()/$step) {
# $saw_values_max = 2*PI() / $step;
# $saw_values_max_at = 'override';
# }
# }
if (($mod eq 'MultipleRings,step=7'
|| $mod eq 'MultipleRings,step=8'
)
&& ($param eq 'dY'
)) {
if (-$saw_values_min > 0.9
&& -$saw_values_min < 1) {
$saw_values_min = -1;
$saw_values_min_at = 'override';
}
if ($saw_values_max > 0.9
&& $saw_values_max < 1) {
$saw_values_max = 1;
$saw_values_max_at = 'override';
}
}
if (($mod eq 'MultipleRings,step=7'
|| $mod eq 'MultipleRings,step=8'
)
&& ($param eq 'dX'
)) {
if (-$saw_values_min > 0.9
&& -$saw_values_min < 1) {
$saw_values_min = -1;
$saw_values_min_at = 'override';
}
}
# approach 360 without ever actually reaching
if (($mod eq 'SacksSpiral'
|| $mod eq 'TheodorusSpiral'
|| $mod eq 'Hypot'
|| $mod eq 'MultipleRings,step=8'
|| $mod eq 'MultipleRings,step=37'
)
&& ($param eq 'Dir4'
)
&& $saw_values_max > 3.7 && $saw_values_max < 4
) {
$saw_values_max = 4;
$saw_values_max_at = 'override';
}
if (($mod eq 'SacksSpiral'
|| $mod eq 'TheodorusSpiral'
|| $mod eq 'Hypot'
|| $mod eq 'MultipleRings,step=8'
|| $mod eq 'MultipleRings,step=37'
)
&& ($param eq 'TDir6'
)
&& $saw_values_max > 5.55 && $saw_values_max < 6) {
$saw_values_max = 6;
$saw_values_max_at = 'override';
}
# approach 0 without ever actually reaching
if (($mod eq 'MultipleRings,step=8'
|| $mod eq 'MultipleRings,step=37'
)
&& ($param eq 'Dir4'
)) {
$saw_values_min = 0;
$saw_values_min_at = 'override';
}
if (($mod eq 'MultipleRings,step=8'
|| $mod eq 'MultipleRings,step=37'
)
&& ($param eq 'TDir6'
)) {
$saw_values_min = 0;
$saw_values_min_at = 'override';
}
# not enough values to see these decreasing
if (($mod eq 'SquareSpiral,wider=37'
)
&& ($param eq 'dY')) {
$saw_values_min = -1;
$saw_values_min_at = 'override';
}
if (($mod eq 'SquareSpiral,wider=37'
)
&& ($param eq 'Dir4')) {
$saw_values_max = 3;
$saw_values_max_at = 'override';
}
if (($mod eq 'SquareSpiral,wider=37'
)
&& ($param eq 'TDir6')) {
$saw_values_max = 4.5;
$saw_values_max_at = 'override';
}
# not enough values to see near supremum
if (($mod eq 'ZOrderCurve,radix=37'
)
&& ($param eq 'Dir4'
|| $param eq 'TDir6'
)) {
$saw_values_max = $values_max;
$saw_values_max_at = 'override';
}
# Turn4 maximum is at N=radix*radix-1
if (($mod eq 'ZOrderCurve,radix=37'
&& $param eq 'Turn4'
&& $i_end < 37*37-1
)) {
$saw_values_max = $values_max;
$saw_values_max_at = 'override';
}
# Turn4 maximum is at N=8191
if (($mod eq 'LCornerReplicate'
&& $param eq 'Turn4'
&& $i_end < 8191
)) {
$saw_values_max = $values_max;
$saw_values_max_at = 'override';
}
if (abs ($values_min - $saw_values_min) > 0.001) {
MyTestHelpers::diag ("$mod $param values_min=$values_min vs saw_values_min=$saw_values_min at $saw_values_min_at (to i_end=$i_end)");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
if (abs ($values_max - $saw_values_max) > 0.001) {
MyTestHelpers::diag ("$mod $param values_max=$values_max vs saw_values_max=$saw_values_max at $saw_values_max_at (to i_end=$i_end)");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
#-------------------
my $increasing = $seq->characteristic('increasing');
my $non_decreasing = $seq->characteristic('non_decreasing');
$increasing ||= 0;
$non_decreasing ||= 0;
# not enough values to see these decreasing
if ($mod eq 'DigitGroups,radix=37'
&& $param eq 'Radius'
&& $i_end < 37*37) {
$saw_characteristic_integer = 0;
}
# not enough values to see these decreasing
if (($mod eq 'ZOrderCurve,radix=9'
|| $mod eq 'ZOrderCurve,radix=37'
|| $mod eq 'PeanoCurve,radix=17'
|| $mod eq 'DigitGroups,radix=37'
|| $mod eq 'SquareSpiral,wider=37'
|| $mod eq 'HexSpiral,wider=37'
|| $mod eq 'HexSpiralSkewed,wider=37'
|| $mod eq 'ComplexPlus,realpart=2'
|| $mod eq 'ComplexPlus,realpart=3'
|| $mod eq 'ComplexPlus,realpart=4'
|| $mod eq 'ComplexPlus,realpart=5'
|| $mod eq 'ComplexMinus,realpart=3'
|| $mod eq 'ComplexMinus,realpart=4'
|| $mod eq 'ComplexMinus,realpart=5'
)
&& ($param eq 'Y'
|| $param eq 'Product')) {
$saw_increasing_at = 'override';
$saw_increasing = 0;
$saw_non_decreasing = 0;
}
# not enough values to see these decreasing
if (($mod eq 'ComplexPlus,realpart=2'
|| $mod eq 'ComplexPlus,realpart=3'
|| $mod eq 'ComplexPlus,realpart=4'
|| $mod eq 'ComplexPlus,realpart=5'
|| $mod eq 'ComplexMinus,realpart=5'
|| $mod eq 'TerdragonMidpoint'
|| $mod eq 'TerdragonMidpoint,arms=2'
|| $mod eq 'TerdragonMidpoint,arms=3'
|| $mod eq 'TerdragonCurve'
|| $mod eq 'TerdragonCurve,arms=2'
|| $mod eq 'TerdragonCurve,arms=3'
|| $mod eq 'TerdragonRounded'
|| $mod eq 'Flowsnake'
|| $mod eq 'Flowsnake,arms=2'
|| $mod eq 'FlowsnakeCentres'
|| $mod eq 'FlowsnakeCentres,arms=2'
|| $mod eq 'GosperSide'
|| $mod eq 'GosperIslands'
|| $mod eq 'QuintetCentres'
|| $mod eq 'QuintetCentres,arms=2'
|| $mod eq 'QuintetCentres,arms=3'
)
&& ($param eq 'X_axis'
|| $param eq 'Y_axis'
|| $param eq 'X_neg'
|| $param eq 'Y_neg'
|| $param =~ /Diagonal/
)) {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if ($mod eq 'QuintetCurve'
&& $i_end < 5938 # first decrease
&& $param eq 'Diagonal_SE') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if ($mod eq 'QuintetCentres'
&& $i_end < 5931 # first decreasing
&& $param eq 'Diagonal_SE') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if ($mod eq 'ImaginaryBase,radix=37'
&& $i_end < 1369 # N of first Y coordinate decrease
&& $param eq 'Y') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
# if ($mod eq 'ImaginaryBase,radix=37'
# $param eq 'Diagonal_NW'
# || $param eq 'Diagonal_NW'
# || $param eq 'Diagonal_SS'
# || $param eq 'Diagonal_SE')
# && $i_end < 74) {
# $saw_increasing = 0;
# $saw_increasing_at = 'override';
# $saw_non_decreasing = 0;
# }
if ($mod eq 'ImaginaryHalf,radix=37'
&& $i_end < 1369 # N of first Y coordinate decrease
&& $param eq 'Y') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if ($mod eq 'ImaginaryHalf,radix=37'
&& $i_end < 99974 # first decrease
&& $param eq 'Diagonal') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if ($mod eq 'ImaginaryHalf,radix=37'
&& $i_end < 2702 # first decreasing
&& $param eq 'Diagonal_NW') {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
# not enough values to see these decreasing
if (($mod eq 'DigitGroups,radix=37'
)
&& ($param eq 'X_axis'
|| $param eq 'Y_axis'
)) {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
# not enough values to see these decreasing
if (($mod eq 'PeanoCurve,radix=2'
|| $mod eq 'PeanoCurve,radix=4'
|| $mod eq 'PeanoCurve,radix=5'
|| $mod eq 'PeanoCurve,radix=17'
)
&& ($param eq 'Diagonal'
)) {
$saw_increasing = 0;
$saw_increasing_at = 'override';
$saw_non_decreasing = 0;
}
if (($mod eq 'SquareSpiral,wider=37'
)
&& ($param eq 'Dir4'
|| $param eq 'TDir6')) {
$saw_non_decreasing = 0;
}
if ($count > 1 && $increasing ne $saw_increasing) {
MyTestHelpers::diag ("$mod $param increasing=$increasing vs saw_increasing=$saw_increasing at $saw_increasing_at (to i_end=$i_end)");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
if ($count > 1 && $non_decreasing ne $saw_non_decreasing) {
MyTestHelpers::diag ("$mod $param non_decreasing=$non_decreasing vs saw_non_decreasing=$saw_non_decreasing at $saw_non_decreasing_at (to i_end=$i_end)");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
if ($characteristic_integer != $saw_characteristic_integer) {
MyTestHelpers::diag ("$mod $param characteristic_integer=$characteristic_integer vs saw_characteristic_integer=$saw_characteristic_integer at $saw_characteristic_integer_at");
MyTestHelpers::diag (" (planepath_object ",ref $seq->{'planepath_object'},")");
$bad++;
}
}
}
ok ($bad, 0);
}
}
#------------------------------------------------------------------------------
sub is_nan {
my ($x) = @_;
return !($x==$x);
}
exit 0;
Math-PlanePath-113/xt/slow/GcdRationals-slow.t 0000644 0001750 0001750 00000007176 12136177164 017062 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min','max';
use Test;
plan tests => 637;
use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Smart::Comments;
require Math::PlanePath::GcdRationals;
my @pairs_order_choices
= @{Math::PlanePath::GcdRationals->parameter_info_hash
->{'pairs_order'}->{'choices'}};
#------------------------------------------------------------------------------
# rect_to_n_range()
my $bad = 0;
my $y_min = 1;
my $y_max = 50;
my $x_min = 1;
my $x_max = 50;
foreach my $pairs_order (@pairs_order_choices) {
my $path = Math::PlanePath::GcdRationals->new (pairs_order => $pairs_order);
my $n_start = $path->n_start;
my $report = sub {
MyTestHelpers::diag("$pairs_order ",@_);
$bad++;
};
my %data;
my $data_count;
foreach my $x ($x_min .. $x_max) {
foreach my $y ($y_min .. $y_max) {
my $n = $path->xy_to_n ($x, $y);
$data{$y}{$x} = $n;
$data_count += defined $n;
}
}
MyTestHelpers::diag("$pairs_order data_count ",$data_count);
foreach my $y1 ($y_min .. $y_max) {
foreach my $y2 ($y1 .. $y_max) {
foreach my $x1 ($x_min .. $x_max) {
my $min;
my $max;
foreach my $x2 ($x1 .. $x_max) {
my @col = map {$data{$_}{$x2}} $y1 .. $y2;
@col = grep {defined} @col;
$min = min (grep {defined} $min, @col);
$max = max (grep {defined} $max, @col);
my $want_min = (defined $min ? $min : 1);
my $want_max = (defined $max ? $max : 0);
### @col
### rect: "$x1,$y1 $x2,$y2 expect N=$want_min..$want_max"
my ($got_min, $got_max)
= $path->rect_to_n_range ($x1,$y1, $x2,$y2);
defined $got_min
or &$report ("rect_to_n_range($x1,$y1, $x2,$y2) got_min undef");
defined $got_max
or &$report ("rect_to_n_range($x1,$y1, $x2,$y2) got_max undef");
$got_min >= $n_start
or &$report ("rect_to_n_range() got_min=$got_min is before n_start=$n_start");
if (! defined $min || ! defined $max) {
next; # outside
}
unless ($got_min <= $want_min) {
### $x1
### $y1
### $x2
### $y2
### got: $path->rect_to_n_range ($x1,$y1, $x2,$y2)
### $want_min
### $want_max
### $got_min
### $got_max
### @col
### $data
&$report ("rect_to_n_range($x1,$y1, $x2,$y2) bad min got_min=$got_min want_min=$want_min".(defined $min ? '' : '[nomin]')
);
}
unless ($got_max >= $want_max) {
&$report ("rect_to_n_range($x1,$y1, $x2,$y2 ) bad max got $got_max want $want_max".(defined $max ? '' : '[nomax]'));
}
}
}
}
}
}
ok ($bad, 0);
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/GrayCode-oseq.t 0000644 0001750 0001750 00000027377 12201357501 015175 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::Prime::XS 0.23 'is_prime'; # version 0.23 fix for 1928099
use Test;
plan tests => 13;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
use Math::PlanePath::GrayCode;
use Math::PlanePath::Diagonals;
# uncomment this to run the ### lines
#use Smart::Comments '###';
sub numeq_array {
my ($a1, $a2) = @_;
if (! ref $a1 || ! ref $a2) {
return 0;
}
my $i = 0;
while ($i < @$a1 && $i < @$a2) {
if ($a1->[$i] ne $a2->[$i]) {
return 0;
}
$i++;
}
return (@$a1 == @$a2);
}
sub to_binary_gray {
my ($n, $radix) = @_;
my $digits = [ digit_split_lowtohigh($n,2) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,2);
return digit_join_lowtohigh($digits,2);
}
#------------------------------------------------------------------------------
# A048641 - binary gray cumulative sum
{
my $anum = 'A048641';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 0;
for (my $n = 0; @got < @$bvalues; $n++) {
$cumulative += to_binary_gray($n);
push @got, $cumulative;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray cumulative sum");
}
#------------------------------------------------------------------------------
# A048644 - binary gray cumulative sum difference from triangular(n)
{
my $anum = 'A048644';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 0;
for (my $n = 0; @got < @$bvalues; $n++) {
$cumulative += to_binary_gray($n);
push @got, $cumulative - triangular($n);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray cumulative sum");
}
sub triangular {
my ($n) = @_;
return $n*($n+1)/2;
}
#------------------------------------------------------------------------------
# A048642 - binary gray cumulative product
{
my $anum = 'A048642';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
require Math::BigInt;
my $product = Math::BigInt->new(1);
for (my $n = 0; @got < @$bvalues; $n++) {
$product *= (to_binary_gray($n) || 1);
push @got, $product;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray cumulative product");
}
#------------------------------------------------------------------------------
# A048643 - binary gray cumulative product, diff to factorial(n)
{
my $anum = 'A048643';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
require Math::BigInt;
my $product = Math::BigInt->new(1);
my $factorial = Math::BigInt->new(1);
for (my $n = 0; @got < @$bvalues; $n++) {
$product *= (to_binary_gray($n) || 1);
$factorial *= ($n||1);
push @got, $product - $factorial;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray cumulative product");
}
#------------------------------------------------------------------------------
# A143329 - gray(prime(n)) which is prime too
{
my $anum = 'A143329';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
my $diff;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
next unless is_prime($n);
my $gray = to_binary_gray($n);
next unless is_prime($gray);
push @got, $gray;
}
$diff = MyOEIS::diff_nums(\@got, $bvalues);
if ($diff) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..45]));
MyTestHelpers::diag ("got: ",join(',',@got[0..45]));
}
}
skip (! $bvalues,
$diff, undef,
"$anum - gray(prime(n)) which is prime too");
}
#------------------------------------------------------------------------------
# A143292 - binary gray of primes
{
my $anum = 'A143292';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
next unless is_prime($n);
push @got, to_binary_gray($n);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray of primes");
}
#------------------------------------------------------------------------------
# A005811 - count 1 bits in gray(n), is num runs
{
my $anum = 'A005811';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
my $gray = to_binary_gray($n);
push @got, count_1_bits($gray);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - primes for which binary gray is also prime");
}
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
#------------------------------------------------------------------------------
# A173318 - cumulative count 1 bits in gray(n) ie. of A005811
{
my $anum = 'A173318';
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $cumulative = 0;
for (my $n = 0; @got < @$bvalues; $n++) {
$cumulative += count_1_bits(to_binary_gray($n));
push @got, $cumulative;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - primes for which binary gray is also prime");
}
#------------------------------------------------------------------------------
# A099891 -- triangle cumulative XOR
#
{
my $anum = 'A099891';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my @array;
for (my $y = 0; @got < @$bvalues; $y++) {
my $gray = to_binary_gray($y,$radix);
push @array, [ $gray ];
for (my $x = 1; $x <= $y; $x++) {
$array[$y][$x] = $array[$y-1][$x-1] ^ $array[$y][$x-1];
}
for (my $x = 0; $x <= $y && @got < @$bvalues; $x++) {
push @got, $array[$y][$x];
}
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A195467 -- diagonals powered permutation, starting from perm^0=identity
#
{
my $anum = 'A195467';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
require Math::PlanePath::Diagonals;
my $diagonal_path = Math::PlanePath::Diagonals->new;
for (my $n = $diagonal_path->n_start; @got < @$bvalues; $n++) {
my ($x, $y) = $diagonal_path->n_to_xy ($n);
my $digits = [ digit_split_lowtohigh($y,$radix) ];
foreach (1 .. $x) { # x=0 unpermuted
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
}
push @got, digit_join_lowtohigh($digits,$radix);
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..10]));
MyTestHelpers::diag ("got: ",join(',',@got[0..10]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1);
}
#------------------------------------------------------------------------------
# A064706 - binary gray reflected permutation applied twice
{
my $anum = 'A064706';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
for (my $n = 0; @got < @$bvalues; $n++) {
push @got, to_binary_gray(to_binary_gray($n));
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray applied twice");
}
#------------------------------------------------------------------------------
# A055975 - binary gray first diffs
{
my $anum = 'A055975';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $prev = 0;
for (my $n = 1; @got < @$bvalues; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
my $gray = digit_join_lowtohigh($digits,$radix);
push @got, $gray - $prev;
$prev = $gray;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray first diffs");
}
#------------------------------------------------------------------------------
# A055975 - binary gray first diffs
{
my $anum = 'A055975';
my $radix = 2;
my ($bvalues, $lo, $filename) = MyOEIS::read_values($anum);
my @got;
if ($bvalues) {
my $prev = 0;
for (my $n = 1; @got < @$bvalues; $n++) {
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
my $gray = digit_join_lowtohigh($digits,$radix);
push @got, $gray - $prev;
$prev = $gray;
}
if (! numeq_array(\@got, $bvalues)) {
MyTestHelpers::diag ("bvalues: ",join(',',@{$bvalues}[0..20]));
MyTestHelpers::diag ("got: ",join(',',@got[0..20]));
}
}
skip (! $bvalues,
numeq_array(\@got, $bvalues),
1, "$anum - binary gray first diffs");
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/DragonCurve-more.t 0000644 0001750 0001750 00000005424 12136177170 015710 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::DragonCurve;
use Test;
plan tests => 28;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
use MyOEIS;
# uncomment this to run the ### lines
#use Smart::Comments '###';
#------------------------------------------------------------------------------
# Lmin,Lmax Wmin,Wmax claimed in the pod
{
my $path = Math::PlanePath::DragonCurve->new;
my $xmax = 0;
my $xmin = 0;
my $ymax = 0;
my $ymin = 0;
my $n = 0;
foreach my $level (2, 4, 8, 10, 12, 14, 16) {
my $k = $level / 2;
my $Nlevel = 2**$level;
for ( ; $n <= $Nlevel; $n++) {
my ($x,$y) = $path->n_to_xy($n);
$xmax = max ($xmax, $x);
$xmin = min ($xmin, $x);
$ymax = max ($ymax, $y);
$ymin = min ($ymin, $y);
}
my $Lmax = $ymax;
my $Lmin = $ymin;
my $Wmax = $xmax;
my $Wmin = $xmin;
foreach (2 .. $k) {
( $Lmax, $Lmin, $Wmax, $Wmin)
= (-$Wmin, -$Wmax, $Lmax, $Lmin); # rotate -90
}
my $calc_Lmax = calc_Lmax($k);
my $calc_Lmin = calc_Lmin($k);
my $calc_Wmax = calc_Wmax($k);
my $calc_Wmin = calc_Wmin($k);
ok ($calc_Lmax, $Lmax, "Lmax k=$k");
ok ($calc_Lmin, $Lmin, "Lmin k=$k");
ok ($calc_Wmax, $Wmax, "Wmax k=$k");
ok ($calc_Wmin, $Wmin, "Wmin k=$k");
}
}
sub calc_Lmax {
my ($k) = @_;
# Lmax = (7*2^k - 4)/6 if k even
# (7*2^k - 2)/6 if k odd
if ($k & 1) {
return (7*2**$k - 2) / 6;
} else {
return (7*2**$k - 4) / 6;
}
}
sub calc_Lmin {
my ($k) = @_;
# Lmin = - (2^k - 1)/3 if k even
# - (2^k - 2)/3 if k odd
if ($k & 1) {
return - (2**$k - 2) / 3;
} else {
return - (2**$k - 1) / 3;
}
}
sub calc_Wmax {
my ($k) = @_;
# Wmax = (2*2^k - 1) / 3 if k even
# (2*2^k - 2) / 3 if k odd
if ($k & 1) {
return (2*2**$k - 1) / 3;
} else {
return (2*2**$k - 2) / 3;
}
}
sub calc_Wmin {
my ($k) = @_;
return calc_Lmin($k);
}
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/xt/0-Test-Pod.t 0000755 0001750 0001750 00000001751 11655356337 014340 0 ustar gg gg #!/usr/bin/perl -w
# 0-Test-Pod.t -- run Test::Pod if available
# Copyright 2009, 2010, 2011 Kevin Ryde
# 0-Test-Pod.t is shared by several distributions.
#
# 0-Test-Pod.t 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, or (at your option) any later
# version.
#
# 0-Test-Pod.t 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 file. If not, see .
use 5.004;
use strict;
use Test::More;
# all_pod_files_ok() is new in Test::Pod 1.00
#
eval 'use Test::Pod 1.00; 1'
or plan skip_all => "due to Test::Pod 1.00 not available -- $@";
Test::Pod::all_pod_files_ok();
exit 0;
Math-PlanePath-113/xt/oeis-xrefs.t 0000755 0001750 0001750 00000012702 12136177231 014613 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Check that OEIS A-numbers listed in lib/Math/PlanePath/Foo.pm files have
# code exercising them in one of the xt/oeis/*-oeis.t scripts.
#
# Check that A-numbers are not duplicated among the .pm files, since that's
# often a cut-and-paste mistake.
#
# Check that A-numbers are not duplicated among xt/oeis/*-oeis.t scripts,
# since normally only need to exercise a claimed path sequence once. Except
# often that's not true since the same sequence can arise in separate ways.
# But for now demand duplication is explicitly listed here.
#
use 5.005;
use strict;
use FindBin;
use ExtUtils::Manifest;
use File::Spec;
use File::Slurp;
use Test::More;
use List::MoreUtils;
use lib 't','xt';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings(); }
# uncomment this to run the ### lines
#use Smart::Comments;
# new in 5.6, so unless got it separately with 5.005
plan tests => 1;
my $toplevel_dir = File::Spec->catdir ($FindBin::Bin, File::Spec->updir);
my $manifest_file = File::Spec->catfile ($toplevel_dir, 'MANIFEST');
my $manifest = ExtUtils::Manifest::maniread ($manifest_file);
my $bad = 0;
my $RE_OEIS_anum = qr/A\d{6,7}/;
#------------------------------------------------------------------------------
my %path_seq_anums;
foreach my $seq_filename ('lib/Math/NumSeq/PlanePathCoord.pm',
'lib/Math/NumSeq/PlanePathN.pm',
'lib/Math/NumSeq/PlanePathDelta.pm',
'lib/Math/NumSeq/PlanePathTurn.pm',
) {
open my $fh, '<', $seq_filename or die "Cannot open $seq_filename";
while (<$fh>) {
if (/^\s*# OEIS-(Catalogue|Other): +(A\d+)([^#]+)/) {
my $anum = $2;
my @args = split /\s/, $3;
my %args = map { split /=/, $_, 2 } @args;
### %args
my $planepath = $args{'planepath'} || die "Oops, no planepath parameter";
my ($path_name, @path_args) = split /,/, $planepath;
push @{$path_seq_anums{$path_name}}, $anum;
}
}
}
foreach (values %path_seq_anums) {
$_ = [ List::MoreUtils::uniq(@$_) ];
}
#------------------------------------------------------------------------------
my @module_filenames
= grep {m{^lib/Math/PlanePath/[^/]+\.pm$}} keys %$manifest;
@module_filenames = sort @module_filenames;
diag "module count ",scalar(@module_filenames);
my @path_names = map {m{([^/]+)\.pm$}
or die "Oops, unmatched module filename $_";
$1} @module_filenames;
sub path_pod_anums {
my ($path_name) = @_;
my $filename = "lib/Math/PlanePath/$path_name.pm";
open my $fh, '<', $filename
or die "Oops, cannot open module filename $filename";
my @ret;
while (<$fh>) {
if (/^ +($RE_OEIS_anum)/) {
push @ret, $1;
}
}
return @ret;
}
sub path_checked_anums {
my ($path_name) = @_;
return (path_xt_anums ($path_name),
@{$path_seq_anums{$path_name} || []});
}
sub path_xt_anums {
my ($path_name) = @_;
my @ret;
if (open my $fh, '<', "xt/oeis/$path_name-oeis.t") {
while (<$fh>) {
if (/^[^#]*\$anum = '($RE_OEIS_anum)'/mg) {
push @ret, $1;
}
if (/^[^#]*anum => '($RE_OEIS_anum)'/mg) {
push @ret, $1;
}
}
}
return @ret;
}
sub str_duplicates {
my %seen;
return map {$seen{$_}++ == 1 ? ($_) : ()} @_;
}
foreach my $path_name (@path_names) {
my @pod_anums = path_pod_anums ($path_name);
my @checked_anums = path_checked_anums ($path_name);
my %pod_anums = map {$_=>1} @pod_anums;
my %checked_anums = map {$_=>1} @checked_anums;
foreach my $anum (str_duplicates(@pod_anums)) {
diag "Math::PlanePath::$path_name duplicate pod $anum";
}
@pod_anums = List::MoreUtils::uniq(@pod_anums);
foreach my $anum (str_duplicates(@checked_anums)) {
next if $anum eq 'A000012'; # all ones
next if $anum eq 'A000027'; # 1,2,3 naturals
next if $anum eq 'A005408'; # odd 2n+1
diag "Math::PlanePath::$path_name duplicate check $anum";
}
@checked_anums = List::MoreUtils::uniq(@checked_anums);
diag "";
foreach my $anum (@pod_anums) {
if (! exists $checked_anums{$anum}) {
diag "Math::PlanePath::$path_name pod anum $anum not checked";
}
}
foreach my $anum (@checked_anums) {
next if $anum eq 'A000004'; # all zeros
next if $anum eq 'A000012'; # all ones
next if $anum eq 'A001477'; # integers 0,1,2,3
next if $anum eq 'A001489'; # negative integers 0,-1,-2,-3
next if $anum eq 'A081274'; # oeis duplicate
next if $anum eq 'A000035'; # 0,1 reps
next if $anum eq 'A059841'; # 1,0 reps
next if $anum eq 'A165211'; # 0,1,0,1, 1,0,1,0, repeating
if (! exists $pod_anums{$anum}) {
diag "Math::PlanePath::$path_name checked anum $anum not in pod";
}
}
}
is ($bad, 0);
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/Makefile.PL 0000755 0001750 0001750 00000005123 12132100404 013640 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use ExtUtils::MakeMaker;
WriteMakefile
(NAME => 'Math-PlanePath',
ABSTRACT => 'Mathematical paths through the 2-D plane.',
VERSION_FROM => 'lib/Math/PlanePath.pm',
PREREQ_PM => {
'Math::Libm' => 0, # for hypot() mainly
'List::Util' => 0,
'constant' => '1.02', # 1.02 for leading underscore
'constant::defer' => 5, # v.5 for 5.6 fixes
# only for testing
'Test' => 0,
},
AUTHOR => 'Kevin Ryde ',
LICENSE => 'gpl',
SIGN => 1,
MIN_PERL_VERSION => '5.004',
META_MERGE =>
{ resources =>
{ homepage => 'http://user42.tuxfamily.org/math-planepath/index.html',
license => 'http://www.gnu.org/licenses/gpl.html',
},
no_index => { directory=>['devel','xt'],
# in Math-PlanePath-Toothpick but added to by
# Math::NumSeq::PlanePathCoord etc
package => [ 'Math::PlanePath::ToothpickTree',
'Math::PlanePath::ToothpickReplicate',
'Math::PlanePath::ToothpickUpist',
'Math::PlanePath::LCornerTree',
'Math::PlanePath::LCornerReplicate',
'Math::PlanePath::OneOfEight',
],
},
optional_features =>
{ maximum_tests =>
{ description => 'Have "make test" do as much as possible.',
requires => { 'Data::Float' => 0,
'Math::BigInt' => 0,
'Math::BigInt::Lite' => 0,
'Math::BigFloat' => '1.993',
'Math::BigRat' => 0,
},
},
},
},
);
Math-PlanePath-113/examples/ 0002755 0001750 0001750 00000000000 12255673733 013534 5 ustar gg gg Math-PlanePath-113/examples/knights-oeis.pl 0000755 0001750 0001750 00000003560 12041154023 016455 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl knights-oeis.pl
#
# This spot of code prints sequence A068608 of Sloane's On-Line Encyclopedia
# of Integer Sequences
#
# http://oeis.org/A068608
#
# which is the infinite knight's tour path of Math::PlanePath::KnightSpiral
# with the X,Y positions numbered according to the SquareSpiral and thus
# giving an integer sequence
#
# 1, 10, 3, 16, 19, 22, 9, 12, 15, 18, 7, 24, 11, 14, ...
#
# All points in the first quadrant are reached by both paths, so this is a
# permutation of the integers.
#
# There's eight variations on the sequence. 2 directions clockwise and
# anti-clockwise and 4 sides to start from relative to the side the square
# spiral numbering starts from.
#
# A068608
# A068609
# A068610
# A068611
# A068612
# A068613
# A068614
# A068615
#
use 5.004;
use strict;
use Math::PlanePath::KnightSpiral;
use Math::PlanePath::SquareSpiral;
my $knights = Math::PlanePath::KnightSpiral->new;
my $square = Math::PlanePath::SquareSpiral->new;
foreach my $n ($knights->n_start .. 20) {
my ($x, $y) = $knights->n_to_xy ($n);
my $sq_n = $square->xy_to_n ($x, $y);
print "$sq_n, ";
}
print "...\n";
exit 0;
Math-PlanePath-113/examples/cellular-rules.pl 0000755 0001750 0001750 00000006361 12041153426 017014 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl cellular-rules.pl
#
# Print the patterns from the CellularRule paths with "*"s.
# Rules with the same output are listed together.
#
# Implementation:
#
# Points are plotted by looping $n until its $y coordinate is beyond the
# desired maximum rows. @rows is an array of strings of length 2*size+1
# spaces each in which "*"s are applied to plot points.
#
# Another way to plot would be to loop over $x,$y for the desired rectangle
# and look at $n=$path->xy_to_n($x,$y) to see which cells have defined($n).
# Characters could be appended or join(map{}) to make an output $str in that
# case. Going by $n should be fastest for sparse patterns, though
# CellularRule is not blindingly quick either way.
#
# See Cellular::Automata::Wolfram for the same but with more options and a
# graphics file output.
#
use 5.004;
use strict;
use Math::PlanePath::CellularRule;
my $numrows = 15; # size of each printout
my %seen;
my $count = 0;
my $mirror_count = 0;
my $finite_count = 0;
my @strs;
my @rules_list;
my @mirror_of;
foreach my $rule (0 .. 255) {
my $path = Math::PlanePath::CellularRule->new (rule => $rule);
my @rows = (' ' x (2*$numrows+1)) x ($numrows+1); # strings of spaces
for (my $n = $path->n_start; ; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or last; # some patterns are only finitely many N values
last if $y > $numrows; # stop at $numrows+1 many rows
substr($rows[$y], $x+$numrows, 1) = '*';
}
@rows = reverse @rows; # print rows going up the page
my $str = join("\n",@rows); # string of all rows
my $seen_rule = $seen{$str}; # possible previous rule giving this $str
if (defined $seen_rule) {
# $str is a repeat of an output already seen, note this $rule with that
$rules_list[$seen_rule] .= ",$rule";
next;
}
my $mirror_str = join("\n", map {scalar(reverse)} @rows);
my $mirror_rule = $seen{$mirror_str};
if (defined $mirror_rule) {
$mirror_of[$mirror_rule] = " (mirror image is rule $rule)";
$mirror_of[$rule] = " (mirror image of rule $mirror_rule)";
$mirror_count++;
}
$strs[$rule] = $str;
$rules_list[$rule] = $rule;
$seen{$str} = $rule;
$count++;
if ($rows[0] =~ /^ *$/) {
$finite_count++;
}
}
foreach my $rule (0 .. 255) {
my $str = $strs[$rule] || next;
print "rule=$rules_list[$rule]", $mirror_of[$rule]||'', "\n";
print "\n$strs[$rule]\n\n";
}
my $unmirrored_count = $count - $mirror_count;
print "Total $count different rule patterns\n";
print "$mirror_count are mirror images of another\n";
print "$finite_count stop after a few cells\n";
exit 0;
Math-PlanePath-113/examples/koch-svg.pl 0000644 0001750 0001750 00000005310 12041154170 015565 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl koch-svg.pl >output.svg
# perl koch-svg.pl LEVEL >output.svg
#
# Print SVG format graphics to standard output for a Koch snowflake curve of
# given LEVEL fineness. The default level is 4.
#
# The range of N values to plot follows the formulas in the
# Math::PlanePath::KochSnowflakes module POD.
#
# The svg output size is a fixed 300x300, but of course the point of svg is
# that it can be resized by a graphics viewer program.
use 5.006;
use strict;
use warnings;
use List::Util 'min';
use Math::PlanePath::KochSnowflakes;
my $path = Math::PlanePath::KochSnowflakes->new;
my $level = $ARGV[0] || 4;
my $width = 300;
my $height = 300;
# use the svg transform="translate()" to centre the origin in the viewport,
# but don't use its scale() to shrink the path X,Y coordinates, just in case
# the factor 1/4^level becomes very small
my $xcentre = $width / 2;
my $ycentre = $height / 2;
print <<"HERE";
HERE
Math-PlanePath-113/examples/ulam-spiral-xpm.pl 0000755 0001750 0001750 00000006005 12041155744 017111 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl ulam-spiral-xpm.pl >/tmp/foo.xpm # write image file
# xzgv /tmp/foo.xpm # view file
#
# This is a bit of fun drawing Ulam's spiral of primes in the SquareSpiral
# path. The output is XPM format (which is plain text) and any good image
# viewer program should display it.
#
# Optional args
#
# perl ulam-spiral-xpm.pl SIZE
# or
# perl ulam-spiral-xpm.pl SIZE SCALE
#
# make the image SIZExSIZE pixels, and SCALE to expand each point to a
# SCALExSCALE square instead of a single pixel.
#
use 5.004;
use strict;
use Math::PlanePath::SquareSpiral;
my $size = 200;
my $scale = 1;
if (@ARGV >= 2) {
$scale = $ARGV[1];
}
if (@ARGV >= 1) {
$size = $ARGV[0];
}
my $path = Math::PlanePath::SquareSpiral->new;
my $x_origin = int($size / 2);
my $y_origin = int($size / 2);
my ($n_lo, $n_hi)
= $path->rect_to_n_range (-$x_origin, -$y_origin,
-$x_origin+$size, -$y_origin+$size);
# Find the prime numbers 2 to $n_hi by sieve of Eratosthenes.
# Could also use Math::Prime::TiedArray or Math::Prime::XS.
#
my @primes = (0, # 0
0, # 1
1, # 2 prime
1, # 3 prime
(0,1) x ($n_hi/2)); # rest alternately even/odd
my $i = 3;
foreach my $i (3 .. int(sqrt($n_hi)) + 1) {
next unless $primes[$i];
foreach (my $j = 2*$i; $j <= $n_hi; $j += $i) {
$primes[$j] = 0;
}
}
# Draw the primes into an array of rows strings.
#
my @rows = (' ' x $size) x $size;
foreach my $n ($n_lo .. $n_hi) {
next unless $primes[$n];
my ($x, $y) = $path->n_to_xy ($n);
$x = $x + $x_origin;
$y = $y_origin - $y; # inverted
# $n_hi is an over-estimate in general, check x,y actually in desired size
if ($x >= 0 && $x < $size && $y >= 0 && $y < $size) {
substr ($rows[$y], $x,1) = '*';
}
}
# Expand @rows points by $scale, horizontally and vertically.
#
if ($scale > 1) {
foreach (@rows) {
s{(.)}{$1 x $scale}eg; # expand horizontally
}
@rows = map { ($_) x $scale} @rows; # expand vertically
$size *= $scale;
}
# XPM format is easy to print.
# Output is about 1 byte per pixel.
#
print <<"HERE";
/* XPM */
static char *ulam_spiral_xpm_pl[] = {
"$size $size 2 1",
" c black",
"* c white",
HERE
foreach my $row (@rows) {
print "\"$row\",\n";
}
print "};\n";
exit 0;
Math-PlanePath-113/examples/sacks-xpm.pl 0000755 0001750 0001750 00000003627 12041155624 015773 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl sacks-xpm.pl >/tmp/foo.xpm # write image file
# xgzv /tmp/foo.xpm # view file
#
# This spot of code generates a big .xpm file showing all points of the
# SacksSpiral. XPM is a text format and can be generated quite easily as
# row strings. Use a graphics viewer program to look at it.
#
use 5.004;
use strict;
use POSIX ();
use Math::PlanePath::SacksSpiral;
my $width = 800;
my $height = 600;
my $spacing = 10;
my $path = Math::PlanePath::SacksSpiral->new;
my $x_origin = int($width / 2);
my $y_origin = int($height / 2);
my $n_max = ($x_origin/$spacing+2)**2 + ($y_origin/$spacing+2)**2;
my @rows = (' ' x $width) x $height;
foreach my $n ($path->n_start .. $n_max) {
my ($x, $y) = $path->n_to_xy ($n);
$x *= $spacing;
$y *= $spacing;
$x = $x + $x_origin;
$y = $y_origin - $y; # inverted
$x = POSIX::floor ($x + 0.5); # round
$y = POSIX::floor ($y + 0.5);
if ($x >= 0 && $x < $width && $y >= 0 && $y < $height) {
substr ($rows[$y], $x,1) = '*';
}
}
print <<"HERE";
/* XPM */
static char *sacks_xpm_pl[] = {
"$width $height 2 1",
" c black",
"* c white",
HERE
foreach my $row (@rows) {
print "\"$row\",\n";
}
print "};\n";
exit 0;
Math-PlanePath-113/examples/hilbert-path.pl 0000755 0001750 0001750 00000005032 12041154004 016427 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl hilbert-lines.pl
#
# This is a bit of fun printing the HilbertCurve path in ascii. It follows
# the terminal width if you've got Term::Size, otherwise 79x23.
#
# Enough curve is drawn to fill the whole output size, clipped when the path
# goes outside the output bounds. You could instead stop at say
#
# $n_hi = 2**6;
#
# to see just a square portion of the curve.
#
# The $scale variable spaces out the points. 3 apart is good, or tighten it
# up to 2 to fit more on the screen.
#
# The output has Y increasing down the screen. It could be instead printed
# up the screen in the final output by going $y from $height-1 down to 0.
#
use 5.004;
use strict;
use Math::PlanePath::HilbertCurve;
my $width = 79;
my $height = 23;
my $scale = 3;
if (eval { require Term::Size }) {
my ($w, $h) = Term::Size::chars();
if ($w) { $width = $w - 1; }
if ($h) { $height = $h - 1; }
}
my $x = 0;
my $y = 0;
my %grid;
# write $char at $x,$y in %grid
sub plot {
my ($char) = @_;
if ($x < $width && $y < $height) {
$grid{$x}{$y} = $char;
}
}
# at the origin 0,0
plot('+');
my $path = Math::PlanePath::HilbertCurve->new;
my $path_width = int($width / $scale) + 1;
my $path_height = int($height / $scale) + 1;
my ($n_lo, $n_hi) = $path->rect_to_n_range (0,0, $path_width,$path_height);
foreach my $n (1 .. $n_hi) {
my ($next_x, $next_y) = $path->n_to_xy ($n);
$next_x *= $scale;
$next_y *= $scale;
while ($x > $next_x) { # draw to left
$x--;
plot ('-');
}
while ($x < $next_x) { # draw to right
$x++;
plot ('-');
}
while ($y > $next_y) { # draw up
$y--;
plot ('|');
}
while ($y < $next_y) { # draw down
$y++;
plot ('|');
}
plot ('+');
}
foreach my $y (0 .. $height-1) {
foreach my $x (0 .. $width-1) {
print $grid{$x}{$y} || ' ';
}
print "\n";
}
exit 0;
Math-PlanePath-113/examples/rationals-tree.pl 0000644 0001750 0001750 00000010675 12136175114 017015 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl rationals-tree.pl
#
# Print the RationalsTree paths in tree form.
#
use 5.004;
use strict;
use List::Util 'max';
use Math::PlanePath::RationalsTree;
use Math::PlanePath::FractionsTree;
sub print_as_fractions {
my ($path) = @_;
my $n = $path->n_start;
foreach (1) {
my ($x,$y) = $path->n_to_xy($n++);
print centre("$x/$y",64);
}
print "\n";
print " /------------- -------------\\\n";
foreach (1 .. 2) {
my ($x,$y) = $path->n_to_xy($n++);
print centre("$x/$y",32);
}
print "\n";
print " /---- ----\\ /---- ----\\\n";
foreach (1 .. 4) {
my ($x,$y) = $path->n_to_xy($n++);
print centre("$x/$y",16);
}
print "\n";
print " / \\ / \\ / \\ / \\\n";
foreach (1 .. 8) {
my ($x,$y) = $path->n_to_xy($n++);
print centre("$x/$y",8);
}
print "\n";
print " / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\\n";
foreach (16 .. 31) {
my ($x,$y) = $path->n_to_xy($n++);
print centre("$x/$y",4);
}
print "\n";
print "\n";
}
sub centre {
my ($str, $width) = @_;
my $extra = max (0, $width - length($str));
my $left = int($extra/2);
my $right = $extra - $left;
return ' 'x$left . $str . ' 'x$right;
}
sub xy_to_cfrac_str {
my ($x,$y) = @_;
my @quotients;
while ($x > 0 && $y > 0) {
push @quotients, int($x/$y);
$x %= $y;
($x,$y) = ($y,$x);
}
return "[".join(',',@quotients)."]";
}
sub print_as_cfracs {
my ($path) = @_;
my $n = $path->n_start;
foreach (1) {
my ($x,$y) = $path->n_to_xy($n++);
print centre(xy_to_cfrac_str($x,$y), 72);
}
print "\n";
print " /--------------- ---------------\\\n";
foreach (1 .. 2) {
my ($x,$y) = $path->n_to_xy($n++);
print centre(xy_to_cfrac_str($x,$y), 36);
}
print "\n";
print " /----- -----\\ /----- -----\\\n";
foreach (1 .. 4) {
my ($x,$y) = $path->n_to_xy($n++);
print centre(xy_to_cfrac_str($x,$y), 18);
}
print "\n";
print " / \\ / \\ / \\ / \\\n";
foreach (1 .. 8) {
my ($x,$y) = $path->n_to_xy($n++);
print centre(xy_to_cfrac_str($x,$y), 9);
}
print "\n";
print "\n";
}
#------------------------------------------------------------------------------
my $rationals_type_arrayref
= Math::PlanePath::RationalsTree->parameter_info_hash()->{'tree_type'}->{'choices'};
my $fractions_type_arrayref
= Math::PlanePath::FractionsTree->parameter_info_hash()->{'tree_type'}->{'choices'};
print "RationalsTree\n";
print "-------------\n\n";
foreach my $tree_type (@$rationals_type_arrayref) {
print "$tree_type tree\n";
my $path = Math::PlanePath::RationalsTree->new
(tree_type => $tree_type);
print_as_fractions ($path);
}
print "\n";
print "FractionsTree\n";
print "-------------\n\n";
foreach my $tree_type (@$fractions_type_arrayref) {
print "$tree_type tree\n";
my $path = Math::PlanePath::FractionsTree->new
(tree_type => $tree_type);
print_as_fractions ($path);
}
print "\n";
print "-----------------------------------------------------------------------\n";
print "Or written as continued fraction quotients.\n";
print "\n";
print "RationalsTree\n";
print "-------------\n\n";
foreach my $tree_type (@$rationals_type_arrayref) {
print "$tree_type tree\n";
my $path = Math::PlanePath::RationalsTree->new
(tree_type => $tree_type);
print_as_cfracs ($path);
}
print "\n";
print "FractionsTree\n";
print "-------------\n\n";
foreach my $tree_type (@$fractions_type_arrayref) {
print "$tree_type tree\n";
my $path = Math::PlanePath::FractionsTree->new
(tree_type => $tree_type);
print_as_cfracs ($path);
}
exit 0;
Math-PlanePath-113/examples/cretan-walls.pl 0000644 0001750 0001750 00000004360 11746612502 016455 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl cretan-walls.pl
#
# This is a bit of fun carving out the CretanLabyrinth from a solid block of
# "*"s, thus leaving those "*"s representing the walls of the labyrinth.
#
# The $spacing variable is how widely to spread the path, for thicker walls.
# The $width,$height sizes are chosen to make a whole 4-way cycle.
#
# The way the arms align means the entrance to the labyrinth is at the
# bottom right corner. In real labyrinths its usual to omit the lower right
# bit of wall so the entrance is in the middle of the right side.
#
use 5.004;
use strict;
use Math::PlanePath::CretanLabyrinth;
my $spacing = 2;
my $width = $spacing * 14 - 1;
my $height = $spacing * 16 - 1;
my $path = Math::PlanePath::CretanLabyrinth->new;
my $x_origin = int($width / 2) + $spacing;
my $y_origin = int($height / 2);
my @rows = ('*' x $width) x $height; # array of strings
sub plot {
my ($x,$y,$char) = @_;
if ($x >= 0 && $x < $width
&& $y >= 0 && $y < $height) {
substr($rows[$y], $x, 1) = $char;
}
}
my ($n_lo, $n_hi)
= $path->rect_to_n_range (-$x_origin,-$y_origin, $x_origin,$y_origin);
my $x = $x_origin;
my $y = $y_origin;
plot($x,$y,'_');
foreach my $n ($n_lo+1 .. $n_hi) {
my ($next_x, $next_y) = $path->n_to_xy ($n);
$next_x *= $spacing;
$next_y *= $spacing;
$next_x += $x_origin;
$next_y += $y_origin;
while ($x != $next_x) {
$x -= ($x <=> $next_x);
plot($x,$y,' ');
}
while ($y != $next_y) {
$y -= ($y <=> $next_y);
plot($x,$y,' ');
}
}
foreach my $row (reverse @rows) {
print "$row\n";
}
exit 0;
Math-PlanePath-113/examples/hilbert-oeis.pl 0000755 0001750 0001750 00000004256 12066001433 016445 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl hilbert-oeis.pl
#
# This spot of code prints sequence A163359 of Sloane's On-Line Encyclopedia
# of Integer Sequences
#
# http://oeis.org/A163359
#
# which is the Hilbert curve N values which occur on squares numbered
# diagonally in the style of Math::PlanePath::Diagonals,
#
# 0, 3, 1, 4, 2, 14, 5, 7, 13, 15, 58, 6, 8, 12, 16, 59, ...
#
# All points in the first quadrant are reached by both paths, so this is a
# re-ordering or the non-negative integers.
#
# In the code there's a double transpose going on. A163359 is conceived as
# the Hilbert starting downwards and the diagonals numbered from the X axis,
# but the HilbertCurve code goes to the right first and the Diagonals module
# numbers from the Y axis. The effect is the same, ie. that the first
# Hilbert step is the opposite axis as the diagonals are numbered from.
#
# Diagonals option direction=>up could be added to transpose $x,$y to make
# the first Hilbert step the same axis as the diagonal numbering. Doing so
# would give sequence A163357.
#
use 5.004;
use strict;
use Math::PlanePath::HilbertCurve;
use Math::PlanePath::Diagonals;
my $hilbert = Math::PlanePath::HilbertCurve->new;
my $diagonal = Math::PlanePath::Diagonals->new;
print "A163359: ";
foreach my $n ($diagonal->n_start .. 19) {
my ($x, $y) = $diagonal->n_to_xy ($n); # X,Y points by diagonals
my $hilbert_n = $hilbert->xy_to_n ($x, $y); # hilbert N at those points
print "$hilbert_n, ";
}
print "...\n";
exit 0;
Math-PlanePath-113/examples/other/ 0002755 0001750 0001750 00000000000 12255673733 014655 5 ustar gg gg Math-PlanePath-113/examples/other/sierpinski-triangle.m4 0000644 0001750 0001750 00000002435 12241344134 021065 0 ustar gg gg divert(-1)
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: m4 sierpinski-triangle.m4
#
# Plot points of the Sierpinski triangle using a bitwise-and to decide
# whether a given X,Y point should be a "*" or a space.
#
# forloop(varname, start,end, body)
# Expand body with varname successively define()ed to integers "start" to
# "end" inclusive. "start" to "end" can go either increasing or decreasing.
define(`forloop', `define(`$1',$2)$4`'dnl
ifelse($2,$3,,`forloop(`$1',eval($2 + 2*($2 < $3) - 1), $3, `$4')')')
divert`'dnl
forloop(`y',15,0,
`forloop(`i',0,y,` ')dnl indent y many spaces
forloop(`x',0,15,
`ifelse(eval(x&y),0,` *',` ')')
')
Math-PlanePath-113/examples/other/sierpinski-triangle-text.gnuplot 0000644 0001750 0001750 00000003320 12062333616 023215 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: gnuplot sierpinski-triangle-text.gnuplot
#
# Print the Sierpinski triangle pattern with spaces and stars using
# bitwise-and to decide whether or not to plot each X,Y.
#
# *
# * *
# * *
# * * * *
# * *
# * * * *
# * * * *
# * * * * * * * *
#
# Return a space or star string to print at x,y.
# Must have x=0 && ((y+x)%2)==0 && ((y+x)&(y-x))==0 ? "*" : " ")
# Return a string which is row y of the triangle from character
# position x through to the right hand end x==y, inclusive.
row(x,y) = (x<=y ? char(x,y).row(x+1,y) : "\n")
# Return a string of stars, spaces and newlines which is the
# Sierpinski triangle rows from y to limit, inclusive.
# The first row is y=0.
triangle(y,limit) = (y <= limit ? row(-limit,y).triangle(y+1,limit) : "")
# Print rows 0 to 15, which is the order 4.
print triangle(0,15)
exit
Math-PlanePath-113/examples/other/dragon-curve.logo 0000644 0001750 0001750 00000004654 12177346175 020142 0 ustar gg gg #!/usr/bin/ucblogo
; Copyright 2012, 2013 Kevin Ryde
;
; This file is part of Math-PlanePath.
;
; Math-PlanePath 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, or (at your option) any later
; version.
;
; Math-PlanePath 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 Math-PlanePath. If not, see .
; Usage: ucblogo dragon-curve-turns.logo
;
; Plot the dragon curve using bit-twiddling to turn the turtle left or
; right, as described for example in "Turn" of
; Math::PlanePath::DragonCurve and variously elsewhere.
;
; The commented out "dragon.chamfer 256" is an alternative plot with
; the corners rounded off to help see the shape.
; Return the bit above the lowest 1-bit in :n.
; If :n = binary "...z100..00" then the return is "z000..00".
; Eg. n=22 is binary 10110 the lowest 1-bit is the "...1." and the return is
; bit above that "..1.," which is 4.
to bit.above.lowest.1bit :n
output bitand :n (1 + (bitxor :n (:n - 1)))
end
; Return angle +90 or -90 for dragon curve turn at point :n.
; The curve is reckoned as starting from n=0 so the first turn is at n=1.
to dragon.turn.angle :n
output ifelse (bit.above.lowest.1bit :n) = 0 [90] [-90]
end
; Draw :steps many segments of the dragon curve.
to dragon :steps
localmake "step.len 12 ; length of each step
repeat :steps [
forward :step.len
left dragon.turn.angle repcount ; repcount = 1 to :steps inclusive
]
end
; Draw :steps many segments of the dragon curve, with corners chamfered
; off with little 45-degree diagonals.
; Done this way the vertices don't touch.
to dragon.chamfer :steps
localmake "step.len 12 ; length of each step
localmake "straight.frac 0.5 ; fraction of the step to go straight
localmake "straight.len :step.len * :straight.frac
localmake "diagonal.len (:step.len - :straight.len) * sqrt(1/2)
repeat :steps [
localmake "turn (dragon.turn.angle repcount)/2 ; +45 or -45
forward :straight.len
left :turn
forward :diagonal.len
left :turn
]
end
dragon 256
; dragon.chamfer 256
Math-PlanePath-113/examples/other/sierpinski-triangle-replicate.gnuplot 0000644 0001750 0001750 00000003247 12041164144 024204 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: gnuplot sierpinski-triangle-replicate.gnuplot
#
# Plot points of the Sierpinski triangle by replicating sub-parts of
# the pattern according to parameter t in ternary.
#
# The alignment relative to the Y axis can be changed by what
# digit_to_x() does. For example to plot half,
#
# digit_to_x(d) = (d<2 ? 0 : 1)
#
# triangle_x(n) and triangle_y(n) return X,Y coordinates for the
# Sierpinski triangle point number n, for integer n.
triangle_x(n) = (n > 0 ? 2*triangle_x(int(n/3)) + digit_to_x(int(n)%3) : 0)
triangle_y(n) = (n > 0 ? 2*triangle_y(int(n/3)) + digit_to_y(int(n)%3) : 0)
digit_to_x(d) = (d==0 ? 0 : d==1 ? -1 : 1)
digit_to_y(d) = (d==0 ? 0 : 1)
# Plot the Sierpinski triangle to "level" many replications.
# "trange" and "samples" are chosen so the parameter t runs through
# integers t=0 to 3**level-1, inclusive.
#
level=6
set trange [0:3**level-1]
set samples 3**level
set parametric
set key off
plot triangle_x(t), triangle_y(t) with points
pause 100 Math-PlanePath-113/examples/other/dragon-curve.m4 0000644 0001750 0001750 00000013730 12221425116 017474 0 ustar gg gg divert(-1)
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: m4 dragon.m4
#
# This is a bit of fun generating the dragon curve with the predicate
# algorithms of xy_is_visited() from DragonMidpoint and DragonCurve. The
# output is generated row by row and and column by column with no image
# array or storage.
#
# The macros which return a pair of values x,y expand to an unquoted 123,456
# which is suitable as arguments to a further macro. The quoting is slack
# because the values are always integers and so won't suffer unwanted macro
# expansion.
# 0,1 Vertex and segment x,y numbering.
# |
# | Segments are numbered as if a
# |s=0,1 square grid turned anti-clockwise
# | by 45 degrees.
# |
# -1,0 -------- 0,0 -------- 1,0 vertex_to_seg_east(x,y) returns
# s=-1,1 | s=0,0 the segment x,y to the East,
# | so vertex_to_seg_east(0,0) is 0,0
# |
# |s=-1,0 vertex_to_seg_west(x,y) returns
# | the segment x,y to the West,
# 0,-1 so vertex_to_seg_west(0,0) is -1,1
#
define(`vertex_to_seg_east', `eval($1 + $2), eval($2 - $1)')
define(`vertex_to_seg_west', `eval($1 + $2 - 1), eval($2 - $1 + 1)')
define(`vertex_to_seg_south', `eval($1 + $2 - 1), eval($2 - $1)')
# Some past BSD m4 didn't have "&" operator, so mod2(n) using % instead.
# mod2() returns 0,1 even if "%" gives -1 for negative odds.
#
define(`mod2', `ifelse(eval($1 % 2),0,0,1)')
# seg_to_even(x,y) returns x,y moved to an "even" position by subtracting an
# offset in a way which suits the segment predicate test.
#
# seg_offset_y(x,y) is a repeating pattern
#
# | 1,1,0,0
# | 1,1,0,0
# | 0,0,1,1
# | 0,0,1,1
# +---------
#
# seg_offset_x(x,y) is the same but offset by 1 in x,y
#
# | 0,1,1,0
# | 1,0,0,1
# | 1,0,0,1
# | 0,1,1,0
# +---------
#
# Incidentally these offset values also give n which is the segment number
# along the curve. "x_offset XOR y_offset" is 0,1 and is a bit of n from
# low to high.
#
define(`seg_offset_y', `mod2(eval(($1 >> 1) + ($2 >> 1)))')
define(`seg_offset_x', `seg_offset_y(eval($1+1), eval($2+1))')
define(`seg_to_even', `eval($1 - seg_offset_x($1,$2)),
eval($2 - seg_offset_y($1,$2))');
# xy_div_iplus1(x,y) returns x,y divided by complex number i+1.
# So (x+i*y)/(i+1) which means newx = (x+y)/2, newy = (y-x)/2.
# Must have x,y "even", meaning x+y even, so newx and newy are integers.
#
define(`xy_div_iplus1', `eval(($1 + $2)/2), eval(($2 - $1)/2)')
# seg_is_final(x,y) returns 1 if x,y is one of the final four points.
# On these four points xy_div_iplus1(seg_to_even(x,y)) returns x,y
# unchanged, so the seg_pred() recursion does not reduce any further.
#
# .. | ..
# final | final y=+1
# final | final y=0
# -------+--------
# .. | ..
# x=-1 x=0
#
define(`seg_is_final', `eval(($1==-1 || $1==0) && ($2==1 || $2==0))')
# seg_pred(x,y) returns 1 if segment x,y is on the dragon curve.
# If the final point reached is 0,0 then the original x,y was on the curve.
# (If a different final point then x,y was one of four rotated copies of the
# curve.)
#
define(`seg_pred', `ifelse(seg_is_final($1,$2), 1,
`eval($1==0 && $2==0)',
`seg_pred(xy_div_iplus1(seg_to_even($1,$2)))')')
# vertex_pred(x,y) returns 1 if point x,y is on the dragon curve.
# The curve always turns left or right at a vertex, it never crosses itself,
# so if a vertex is visited then either the segment to the east or to the
# west must have been traversed. Prefer ifelse() for the two checks since
# eval() || operator is not a short-circuit.
#
define(`vertex_pred', `ifelse(seg_pred(vertex_to_seg_east($1,$2)),1,1,
`seg_pred(vertex_to_seg_west($1,$2))')')
# forloop(varname, start,end, body)
# Expand body with varname successively define()ed to integers "start" to
# "end" inclusive. "start" to "end" can go either increasing or decreasing.
#
define(`forloop', `define(`$1',$2)$4`'dnl
ifelse($2,$3,,`forloop(`$1',eval($2 + 2*($2 < $3) - 1), $3, `$4')')')
#----------------------------------------------------------------------------
# dragon01(xmin,xmax, ymin,ymax) prints an array of 0s and 1s which are the
# vertex_pred() values. `y' runs from ymax down to ymin so that y
# coordinate increases up the screen.
#
define(`dragon01',
`forloop(`y',$4,$3, `forloop(`x',$1,$2, `vertex_pred(x,y)')
')')
# dragon_ascii(xmin,xmax, ymin,ymax) prints an ascii art dragon curve.
# Each y value results in two output lines. The first has "+" vertices and
# "--" horizontals. The second has "|" verticals.
#
define(`dragon_ascii',
`forloop(`y',$4,$3,
`forloop(`x',$1,$2,
`ifelse(vertex_pred(x,y),1, `+', ` ')dnl
ifelse(seg_pred(vertex_to_seg_east(x,y)), 1, `--', ` ')')
forloop(`x',$1,$2,
`ifelse(seg_pred(vertex_to_seg_south(x,y)), 1, `| ', ` ')')
')')
#--------------------------------------------------------------------------
divert`'dnl
# 0s and 1s directly from vertex_pred().
#
dragon01(-7,23, dnl X range
-11,10) dnl Y range
# ASCII art lines.
#
dragon_ascii(-6,5, dnl X range
-10,2) dnl Y range
Math-PlanePath-113/examples/other/sierpinski-triangle-bitand.gnuplot 0000644 0001750 0001750 00000002646 12177346233 023512 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: gnuplot sierpinski-triangle-replicate.gnuplot
#
# Plot points of the Sierpinski triangle by a bitwise-and to decide
# whether a given X,Y point should be plotted. Points not wanted are
# suppressed by returning NaN.
level=6
size=2**level
# Return X,Y grid coordinates ranging X=0 to size-1 and Y=0 to size-1,
# as t ranges 0 to size*size-1.
x(t) = int(t) % size
y(t) = int(t / size)
# Return true if the X,Y coordinates at t are wanted for the
# Sierpinski triangle.
want(t) = ((x(t) & y(t)) == 0)
triangle_x(t) = (want(t) ? x(t) : NaN)
triangle_y(t) = (want(t) ? y(t) : NaN)
set parametric
set trange [0:size*size-1]
set samples size*size
set key off
plot triangle_x(t),triangle_y(t) with points
pause 100
Math-PlanePath-113/examples/other/dragon-curve.el 0000644 0001750 0001750 00000007712 12241340154 017557 0 ustar gg gg ;; Copyright 2012, 2013 Kevin Ryde
;;
;; This file is part of Math-PlanePath.
;;
;; Math-PlanePath 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, or (at your option) any later
;; version.
;;
;; Math-PlanePath 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 Math-PlanePath. If not, see .
;; Usage: M-x load-file dragon-curve.el
;;
;; And thereafter M-x dragon-picture.
;;
(unless (fboundp 'ignore-errors)
(require 'cl)) ;; Emacs 22 and earlier `ignore-errors'
(defun dragon-ensure-line-above ()
"If point is in the first line of the buffer then insert a new line above."
(when (= (line-beginning-position) (point-min))
(save-excursion
(goto-char (point-min))
(insert "\n"))))
(defun dragon-ensure-column-left ()
"If point is in the first column then insert a new column to the left.
This is designed for use in `picture-mode'."
(when (zerop (current-column))
(save-excursion
(goto-char (point-min))
(insert " ")
(while (= 0 (forward-line 1))
(insert " ")))
(picture-forward-column 1)))
(defun dragon-insert-char (char len)
"Insert CHAR repeated LEN many times.
After each CHAR move point in the current `picture-mode'
direction (per `picture-set-motion' etc).
This is the same as `picture-insert' except in column 0 or row 0
a new row or column is inserted to make room, with existing
buffer contents shifted down or right."
(dotimes (i len)
(dragon-ensure-line-above)
(dragon-ensure-column-left)
(picture-insert char 1)))
(defun dragon-bit-above-lowest-0bit (n)
"Return the bit above the lowest 0-bit in N.
For example N=43 binary \"101011\" has lowest 0-bit at \"...0..\"
and the bit above that is \"..1...\" so return 8 which is that
bit."
(logand n (1+ (logxor n (1+ n)))))
(defun dragon-next-turn-right-p (n)
"Return non-nil if the dragon curve should turn right after segment N.
Segments are numbered from N=0 for the first, so calling with N=0
is whether to turn right at the end of that N=0 segment."
(zerop (dragon-bit-above-lowest-0bit n)))
(defun dragon-picture (len step)
"Draw the dragon curve in a *dragon* buffer.
LEN is the number of segments of the curve to draw.
STEP is the length of each segment, in characters.
Any LEN can be given but a power-of-2 such as 256 shows the
self-similar nature of the curve.
If STEP >= 2 then the segments are lines using \"-\" or \"|\"
characters (`picture-rectangle-h' and `picture-rectangle-v').
If STEP=1 then only \"+\" corners.
There's a `sit-for' delay in the drawing loop to draw the curve
progressively on screen."
(interactive (list (read-number "Length of curve " 256)
(read-number "Each step size " 3)))
(unless (>= step 1)
(error "Step length must be >= 1"))
(switch-to-buffer "*dragon*")
(erase-buffer)
(setq truncate-lines t)
(ignore-errors ;; ignore error if already in picture-mode
(picture-mode))
(dotimes (n len) ;; n=0 to len-1, inclusive
(dragon-insert-char ?+ 1) ;; corner char
(dragon-insert-char (if (zerop picture-vertical-step)
picture-rectangle-h picture-rectangle-v)
(1- step)) ;; line chars
(if (dragon-next-turn-right-p n)
;; turn right
(picture-set-motion (- picture-horizontal-step) picture-vertical-step)
;; turn left
(picture-set-motion picture-horizontal-step (- picture-vertical-step)))
;; delay to display the drawing progressively
(sit-for .01))
(picture-insert ?+ 1) ;; endpoint
(picture-mode-exit)
(goto-char (point-min)))
(dragon-picture 128 2)
Math-PlanePath-113/examples/other/dragon-recursive.gri 0000644 0001750 0001750 00000006443 12217673641 020640 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
`Draw Dragon [ from .x1. .y1. to .x2. .y2. [level .level.] ]'
Draw a dragon curve going from .x1. .y1. to .x2. .y2. with recursion
depth .level.
The total number of line segments for the recursion is 2^level.
level=0 is a straight line from x1,y1 to x2,y2.
The default for x1,y1 and x2,y2 is to draw horizontally from 0,0
to 1,0.
{
new .x1. .y1. .x2. .y2. .level.
.x1. = \.word3.
.y1. = \.word4.
.x2. = \.word6.
.y2. = \.word7.
.level. = \.word9.
if {rpn \.words. 5 >=}
.x2. = 1
.y2. = 0
end if
if {rpn \.words. 7 >=}
.level. = 6
end if
if {rpn 0 .level. <=}
draw line from .x1. .y1. to .x2. .y2.
else
.level. = {rpn .level. 1 -}
# xmid,ymid is half way between x1,y1 and x2,y2 and up at
# right angles away.
#
# xmid,ymid xmid = (x1+x2 + y2-y1)/2
# ^ ^ ymid = (x1-x2 + y1+y2)/2
# / . \
# / . \
# x1,y1 ........... x2,y2
#
new .xmid. .ymid.
.xmid. = {rpn .x1. .x2. + .y2. .y1. - + 2 /}
.ymid. = {rpn .x1. .x2. - .y1. .y2. + + 2 /}
# The recursion is a level-1 dragon from x1,y1 to the midpoint
# and the same from x2,y2 to the midpoint (the latter
# effectively being a revered dragon.)
#
Draw Dragon from .x1. .y1. to .xmid. .ymid. level .level.
Draw Dragon from .x2. .y2. to .xmid. .ymid. level .level.
delete .xmid. .ymid.
end if
delete .x1. .y1. .x2. .y2. .level.
}
# Dragon curve from 0,0 to 1,0 extends out by 1/3 at the ends, so
# extents -0.5 to +1.5 for a bit of margin. The Y extent is the same
# size 2 to make the graph square.
set x axis -0.5 1.5 .25
set y axis -1 1 .25
Draw Dragon
#Draw Dragon from 0 0 to 1 0 level 10
# x1,y1 to x2,y2
# dx = x2-x1
# dy = y2-y1
# xmid = x1 + dx/2 - dy/2
# = x1 + (x2-x1 - (y2-y1))/2
# = (2*x1 + x2-x1 -y2+y1)/2
# = (2*x1 + x2-x1 - y2+y1) / 2
# = (x1+x2 + y1-y2)/2
# ymid = y1 + dy/2 + dx/2
# = (2*y1 + dy + dx)/2
# = (2*y1 + y2-y1 + x2-x1) / 2
# = (y1+y2 + x2-x1) / 2
# xmid = x1 + dx/2 + dy/2
# = x1 + (x2-x1 + y2-y1)/2
# = (x1+x2 + y2-y1)/2
# ymid = y1 + dy/2 - dx/2
# = (2*y1 + y2-y1 + x1-x2) / 2
# = (y1+y2 + x1-x2) / 2
# show " line " .x1. " " .y1. " to " .x2. " " .y2.
# show .x1. " " .y1. " to " .x2. " " .y2. " mid " .xmid. " " .ymid.
# show "second " .x1. " " .y1. " to " .x2. " " .y2. " mid " .xmid. " " .ymid.
# show "level " .level.
Math-PlanePath-113/examples/other/dragon-pgf-plain.tex 0000644 0001750 0001750 00000004665 12246063147 020525 0 ustar gg gg %% Copyright 2013 Kevin Ryde
%%
%% This file is part of Math-PlanePath.
%%
%% Math-PlanePath 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, or (at your option) any later
%% version.
%%
%% Math-PlanePath 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 Math-PlanePath. If not, see .
%% Usage: tex dragon-pgf-latex.tex
%% xdvi dragon-pgf-latex.dvi
%%
%% This a dragon curve drawn with the PGF lindenmayersystems library.
%%
%% http://sourceforge.net/projects/pgf/
%%
%% The PGF manual includes examles of Koch snowflake, Hilbert curve and
%% Sierpinski arrowhead. In the ``spy'' library section there's some
%% magnifications of the Koch and of a quadric curve too.
%%
%% In the rule here \symbol{S} is a second drawing symbol. It draws a
%% line segment the same as F, but the two different symbols let the
%% rules distinguish odd and even position line segments.
%%
%% F and S are always in pairs, F first and S second, F_S_F_S_F_S_F_S.
%% At each even position F expands to a left bend, ie with a "+" turn.
%% At each odd position S expands to a right bend, ie with a "-".
%% This is the "successive approximation" method for generating the
%% curve where each line segment is replaced by a bend to the left or
%% right according as it's at an even or odd position.
%%
%% The sequence of + and - turns resulting in the expansion follows
%% the "bit above lowest 1-bit" rule. This works essentially because
%% the bit above obeys an expansion rule
%%
%% if k even
%% bitabovelowest1bit(2k) = bitabovelowest1bit(k)
%% bitabovelowest1bit(2k+1) = 0 # the "+" in F -> F+S
%%
%% if k odd
%% bitabovelowest1bit(2k) = bitabovelowest1bit(k)
%% bitabovelowest1bit(2k+1) = 1 # the "-" in S -> F-S
%%
\input tikz.tex
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{S}{\pgflsystemdrawforward}
\rule{F -> F+S}
\rule{S -> F-S}
}
\tikzpicture
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=8}]
lindenmayer system;
\endtikzpicture
\bye
Math-PlanePath-113/examples/other/sierpinski-triangle-text.logo 0000644 0001750 0001750 00000003040 12062333621 022460 0 ustar gg gg #!/usr/bin/ucblogo
; Copyright 2012 Kevin Ryde
; This file is part of Math-PlanePath.
;
; Math-PlanePath 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, or (at your option) any later
; version.
;
; Math-PlanePath 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 Math-PlanePath. If not, see .
; Usage: ucblogo sierpinski-triangle-text.logo
;
; Print the Sierpinski triangle pattern in text with spaces and stars,
; using BITAND to decide whether to plot at a given X,Y or not.
;
; :limit determines the padding at the left, and within that limit the
; range of :y to print is arbitrary.
; Print rows of the triangle from 0 to :limit inclusive.
;
; *
; * *
; * *
; * * * *
; * *
; * * * *
; * * * *
; * * * * * * * *
;
make "limit 15
for [y 0 :limit] [
for [x -:limit :y] [
type ifelse (and :y+:x >= 0 ; blank left of triangle
(remainder :y+:x 2) = 0 ; only "even" squares
(bitand :y+:x :y-:x) = 0 ; Sierpinski bit test
) ["*] ["| |] ; star or space
]
print []
]
Math-PlanePath-113/examples/other/dragon-pgf-latex.tex 0000644 0001750 0001750 00000003341 12246063234 020522 0 ustar gg gg %% Copyright 2013 Kevin Ryde
%%
%% This file is part of Math-PlanePath.
%%
%% Math-PlanePath 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, or (at your option) any later
%% version.
%%
%% Math-PlanePath 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 Math-PlanePath. If not, see .
%% Usage: latex dragon-pgf-latex.tex
%% xdvi dragon-pgf-latex.dvi
%% See dragon-pgf-plain.tex for more comments. The F,S here behave
%% the same as there.
%%
%% The rule here is a 45-degree variation which keeps the net
%% direction unchanged after expansion. This means the curve endpoint
%% remains in a fixed direction horizontal no matter what expansion
%% level is applied.
%%
%% Does Mandelbrot's book ``Fractal Geometry of Nature'' have an
%% expansion like this, but maybe with just a single drawing symbol?
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\begin{document}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{S}{\pgflsystemdrawforward}
\rule{F -> -F++S-}
\rule{S -> +F--S+}
}
\foreach \i in {1,...,8} {
\hbox{
order=\i
\hspace{.5em}
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=\i}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
}
\vspace{.5ex}
}
\end{document}
Math-PlanePath-113/examples/other/dragon-curve.gnuplot 0000644 0001750 0001750 00000005547 12041161321 020646 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: gnuplot dragon-curve.gnuplot
#
# Draw the dragon curve by calculating an X,Y position for each
# point n. The plot is in "parametric" mode with t running integers
# 0 to n inclusive.
# Return the position of the highest 1-bit in n.
# The least significant bit is position 0.
# For example n=13 is binary "1101" and the high bit is pos=3.
# If n==0 then the return is 0.
# Arranging the test as n>=2 avoids infinite recursion if n==NaN (any
# comparison involving NaN is always false).
#
high_bit_pos(n) = (n>=2 ? 1+high_bit_pos(int(n/2)) : 0)
# Return 0 or 1 for the bit at position "pos" in n.
# pos==0 is the least significant bit.
#
bit(n,pos) = int(n / 2**pos) & 1
# dragon(n) returns a complex number which is the position of the
# dragon curve at integer point "n". n=0 is the first point and is at
# the origin {0,0}. Then n=1 is at {1,0} which is x=1,y=0, etc. If n
# is not an integer then the point returned is for int(n).
#
# The calculation goes by bits of n from high to low. Gnuplot doesn't
# have iteration in functions, but can go recursively from
# pos=high_bit_pos(n) down to pos=0, inclusive.
#
# mul() rotates by +90 degrees (complex "i") at bit transitions 0->1
# or 1->0. add() is a vector (i+1)**pos for each 1-bit, but turned by
# factor "i" when in a "reversed" section of curve, which is when the
# bit above is also a 1-bit.
#
dragon(n) = dragon_by_bits(n, high_bit_pos(n))
dragon_by_bits(n,pos) \
= (pos>=0 ? add(n,pos) + mul(n,pos)*dragon_by_bits(n,pos-1) : 0)
add(n,pos) = (bit(n,pos) ? (bit(n,pos+1) ? {0,1} * {1,1}**pos \
: {1,1}**pos) \
: 0)
mul(n,pos) = (bit(n,pos) == bit(n,pos+1) ? 1 : {0,1})
# Plot the dragon curve from 0 to "length" with line segments.
# "trange" and "samples" are set so the parameter t runs through
# integers t=0 to t=length inclusive.
#
# Any trange works, it doesn't have to start at 0. But must have
# enough "samples" that all integers t in the range are visited,
# otherwise vertices in the curve would be missed.
#
length=256
set trange [0:length]
set samples length+1
set parametric
set key off
plot real(dragon(t)),imag(dragon(t)) with lines
Math-PlanePath-113/examples/square-numbers.pl 0000755 0001750 0001750 00000003325 12041155563 017033 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl square-numbers.pl
#
# Print the SquareSpiral numbers in a grid like
#
# 37 36 35 34 33 32 31
# 38 17 16 15 14 13 30
# 39 18 5 4 3 12 29
# 40 19 6 1 2 11 28
# 41 20 7 8 9 10 27
# 42 21 22 23 24 25 26
# 43 44 45 46 47 ...
#
# See numbers.pl for a more sophisticated program.
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::SquareSpiral;
my $n_max = 115;
my $path = Math::PlanePath::SquareSpiral->new;
my %rows;
my $x_min = 0;
my $x_max = 0;
my $y_min = 0;
my $y_max = 0;
foreach my $n ($path->n_start .. $n_max) {
my ($x, $y) = $path->n_to_xy ($n);
$rows{$x}{$y} = $n;
$x_min = min($x_min, $x);
$x_max = max($x_max, $x);
$y_min = min($y_min, $y);
$y_max = max($y_max, $y);
}
my $cellwidth = length($n_max) + 2;
foreach my $y (reverse $y_min .. $y_max) {
foreach my $x ($x_min .. $x_max) {
printf ('%*s', $cellwidth, $rows{$x}{$y} || '');
}
print "\n";
}
exit 0;
Math-PlanePath-113/examples/numbers.pl 0000755 0001750 0001750 00000044056 12252763533 015551 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl numbers.pl CLASS...
# perl numbers.pl all
#
# Print the given path CLASS or classes as N numbers in a grid. Eg.
#
# perl numbers.pl SquareSpiral DiamondSpiral
#
# Parameters to the class can be given as
#
# perl numbers.pl SquareSpiral,wider=4
#
# With option "all" print all classes and a selection of their parameters,
# per the table in the code below
#
# perl numbers.pl all
#
# See square-numbers.pl for a simpler program designed just for the
# SquareSpiral. The code here tries to adapt itself to the tty width and
# stops when the width of the numbers to be displayed would be wider than
# the tty.
#
# Stopping when N goes outside the tty means that just the first say 99 or
# so N values will be shown. There's often other bigger N within the X,Y
# grid region, but the first few N show how the path begins, without
# clogging up the output.
#
# The origin 0,0 is kept in the middle of the output, horizontally, to help
# see how much is on each side and to make multiple paths printed line up
# such as the "all" option. Vertically only as many rows as necessary are
# printed.
#
# Paths with fractional X,Y positions like SacksSpiral or VogelFloret are
# rounded to character positions. There's some hard-coded fudge factors to
# try to make them come out nicely.
#
# When an X,Y position is visited more than once multiple N's are shown with
# a comma like "9,24". This can happen for example in the DragonCurve where
# points are visited twice, or when rounding gives the same X,Y for a few
# initial points such as in KochSquareflakes.
#
use 5.004;
use strict;
use POSIX ();
use List::Util 'min', 'max';
my $width = 79;
my $height = 23;
# use Term::Size if available
# chars() can return 0 for unknown size, ignore that
if (eval { require Term::Size }) {
my ($term_width, $term_height) = Term::Size::chars();
if ($term_width) { $width = $term_width - 1; }
if ($term_height) { $height = $term_height - 1; }
}
if (! @ARGV) {
push @ARGV, 'HexSpiral'; # default class to print if no args
}
my @all_classes = ('SquareSpiral',
'SquareSpiral,wider=9',
'DiamondSpiral',
'PentSpiral',
'PentSpiralSkewed',
'HexSpiral',
'HexSpiral,wider=3',
'HexSpiralSkewed',
'HexSpiralSkewed,wider=5',
'HeptSpiralSkewed',
'AnvilSpiral',
'AnvilSpiral,wider=3',
'OctagramSpiral',
'PyramidSpiral',
'PyramidRows',
'PyramidRows,step=5',
'PyramidRows,align=right',
'PyramidRows,align=left,step=4',
'PyramidSides',
'CellularRule,rule=30',
'CellularRule,rule=73',
'CellularRule54',
'CellularRule57',
'CellularRule57,mirror=1',
'CellularRule190',
'CellularRule190,mirror=1',
'TriangleSpiral',
'TriangleSpiralSkewed',
'TriangleSpiralSkewed,skew=right',
'TriangleSpiralSkewed,skew=up',
'TriangleSpiralSkewed,skew=down',
'Diagonals',
'Diagonals,direction=up',
'DiagonalsAlternating',
'DiagonalsOctant',
'DiagonalsOctant,direction=up',
'Staircase',
'StaircaseAlternating',
'StaircaseAlternating,end_type=square',
'Corner',
'Corner,wider=5',
'KnightSpiral',
'CretanLabyrinth',
'SquareArms',
'DiamondArms',
'HexArms',
'GreekKeySpiral',
'GreekKeySpiral,turns=4',
'GreekKeySpiral,turns=1',
'AztecDiamondRings',
'MPeaks',
'SacksSpiral',
'VogelFloret',
'ArchimedeanChords',
'TheodorusSpiral',
'MultipleRings',
'MultipleRings,step=14',
'PixelRings',
'FilledRings',
'Hypot',
'Hypot,points=even',
'Hypot,points=odd',
'HypotOctant',
'HypotOctant,points=even',
'HypotOctant,points=odd',
'TriangularHypot',
'TriangularHypot,points=odd',
'TriangularHypot,points=all',
'TriangularHypot,points=hex',
'TriangularHypot,points=hex_rotated',
'TriangularHypot,points=hex_centred',
'Rows',
'Columns',
'UlamWarburton',
'UlamWarburton,parts=2',
'UlamWarburton,parts=1',
'UlamWarburtonQuarter',
'PeanoCurve',
'PeanoCurve,radix=5',
'WunderlichSerpentine',
'WunderlichSerpentine,serpentine_type=coil',
'WunderlichSerpentine,radix=5,serpentine_type=01001_01110_01000_11111_00010',
'WunderlichMeander',
'HilbertCurve',
'HilbertSpiral',
'ZOrderCurve',
'ZOrderCurve,radix=5',
'GrayCode',
'GrayCode,apply_type=Ts',
'GrayCode,radix=4',
'BetaOmega',
'AR2W2Curve',
'AR2W2Curve,start_shape=D2',
'AR2W2Curve,start_shape=B2',
'AR2W2Curve,start_shape=B1rev',
'AR2W2Curve,start_shape=D1rev',
'AR2W2Curve,start_shape=A2rev',
'KochelCurve',
'DekkingCurve',
'DekkingCentres',
'CincoCurve',
'ImaginaryBase',
'ImaginaryBase,radix=4',
'ImaginaryHalf',
'ImaginaryHalf,radix=4',
'ImaginaryHalf,digit_order=XXY',
'ImaginaryHalf,digit_order=YXX',
'ImaginaryHalf,digit_order=XnXY',
'ImaginaryHalf,digit_order=XnYX',
'ImaginaryHalf,digit_order=YXnX',
'CubicBase',
'CubicBase,radix=4',
'SquareReplicate',
'CornerReplicate',
'LTiling',
'LTiling,L_fill=ends',
'LTiling,L_fill=all',
'DigitGroups',
'FibonacciWordFractal',
'Flowsnake',
'Flowsnake,arms=3',
'FlowsnakeCentres',
'FlowsnakeCentres,arms=3',
'GosperReplicate',
'GosperIslands',
'GosperSide',
'QuintetCurve',
'QuintetCurve,arms=4',
'QuintetCentres',
'QuintetReplicate',
'KochCurve',
'KochPeaks',
'KochSnowflakes',
'KochSquareflakes',
'KochSquareflakes,inward=1',
'QuadricCurve',
'QuadricIslands',
'SierpinskiCurve',
'SierpinskiCurve,arms=8',
'SierpinskiCurveStair',
'SierpinskiCurveStair,arms=2',
'SierpinskiCurveStair,diagonal_length=4',
'HIndexing',
'SierpinskiTriangle',
'SierpinskiTriangle,align=right',
'SierpinskiTriangle,align=left',
'SierpinskiTriangle,align=diagonal',
'SierpinskiArrowhead',
'SierpinskiArrowhead,align=right',
'SierpinskiArrowhead,align=left',
'SierpinskiArrowhead,align=diagonal',
'SierpinskiArrowheadCentres',
'SierpinskiArrowheadCentres,align=right',
'SierpinskiArrowheadCentres,align=left',
'SierpinskiArrowheadCentres,align=diagonal',
'DragonCurve',
'DragonCurve,arms=4',
'DragonRounded',
'DragonRounded,arms=4',
'DragonMidpoint',
'DragonMidpoint,arms=2',
'DragonMidpoint,arms=3',
'DragonMidpoint,arms=4',
'AlternatePaper',
'AlternatePaper,arms=2',
'AlternatePaper,arms=8',
'AlternatePaperMidpoint',
'AlternatePaperMidpoint,arms=2',
'AlternatePaperMidpoint,arms=8',
'CCurve',
'TerdragonCurve',
'TerdragonCurve,arms=6',
'TerdragonRounded',
'TerdragonRounded,arms=6',
'TerdragonMidpoint',
'TerdragonMidpoint,arms=6',
'R5DragonCurve',
'R5DragonCurve,arms=4',
'R5DragonMidpoint',
'R5DragonMidpoint,arms=2',
'R5DragonMidpoint,arms=3',
'R5DragonMidpoint,arms=4',
'ComplexPlus',
'ComplexPlus,realpart=2',
'ComplexMinus',
'ComplexMinus,realpart=2',
'ComplexRevolving',
'PythagoreanTree,tree_type=UAD',
'PythagoreanTree,tree_type=UAD,coordinates=AC',
'PythagoreanTree,tree_type=UAD,coordinates=BC',
'PythagoreanTree,tree_type=UAD,coordinates=PQ',
'PythagoreanTree,tree_type=UAD,coordinates=SM',
'PythagoreanTree,tree_type=UAD,coordinates=SC',
'PythagoreanTree,tree_type=UAD,coordinates=MC',
'PythagoreanTree,tree_type=FB',
'PythagoreanTree,tree_type=FB,coordinates=AC',
'PythagoreanTree,tree_type=FB,coordinates=BC',
'PythagoreanTree,tree_type=FB,coordinates=PQ',
'PythagoreanTree,tree_type=FB,coordinates=SM',
'PythagoreanTree,tree_type=FB,coordinates=SC',
'PythagoreanTree,tree_type=FB,coordinates=MC',
'PythagoreanTree,tree_type=UMT',
'PythagoreanTree,tree_type=UMT,coordinates=AC',
'PythagoreanTree,tree_type=UMT,coordinates=BC',
'PythagoreanTree,tree_type=UMT,coordinates=PQ',
'PythagoreanTree,tree_type=UMT,coordinates=SM',
'PythagoreanTree,tree_type=UMT,coordinates=SC',
'PythagoreanTree,tree_type=UMT,coordinates=MC',
'DiagonalRationals',
'DiagonalRationals,direction=up',
'CoprimeColumns',
'FactorRationals',
'GcdRationals',
'GcdRationals,pairs_order=rows_reverse',
'GcdRationals,pairs_order=diagonals_down',
'GcdRationals,pairs_order=diagonals_up',
'RationalsTree,tree_type=SB',
'RationalsTree,tree_type=CW',
'RationalsTree,tree_type=AYT',
'RationalsTree,tree_type=HCS',
'RationalsTree,tree_type=Bird',
'RationalsTree,tree_type=Drib',
'RationalsTree,tree_type=L',
'FractionsTree',
'ChanTree',
'ChanTree,k=4',
'ChanTree,k=5',
'ChanTree,k=7',
'ChanTree,k=8',
'CfracDigits',
'CfracDigits,radix=3',
'CfracDigits,radix=4',
'CfracDigits,radix=1',
'DivisibleColumns',
'DivisibleColumns,divisor_type=proper',
'WythoffArray',
'PowerArray',
'PowerArray,radix=3',
'PowerArray,radix=4',
# in separate Math-PlanePath-Toothpick
'*ToothpickTree',
'*ToothpickTree,parts=3',
'*ToothpickTree,parts=2',
'*ToothpickTree,parts=1',
'*ToothpickTree,parts=octant',
'*ToothpickTree,parts=octant_up',
'*ToothpickTree,parts=wedge',
'*ToothpickReplicate',
'*ToothpickReplicate,parts=3',
'*ToothpickReplicate,parts=2',
'*ToothpickReplicate,parts=1',
'*ToothpickUpist',
'*ToothpickSpiral',
'*LCornerTree',
'*LCornerTree,parts=3',
'*LCornerTree,parts=2',
'*LCornerTree,parts=1',
'*LCornerTree,parts=octant',
'*LCornerTree,parts=octant+1',
'*LCornerTree,parts=octant_up',
'*LCornerTree,parts=octant_up+1',
'*LCornerTree,parts=wedge',
'*LCornerTree,parts=wedge+1',
'*LCornerTree,parts=diagonal',
'*LCornerTree,parts=diagonal-1',
'*LCornerReplicate',
'*OneOfEight',
'*OneOfEight,parts=4',
'*OneOfEight,parts=1',
'*OneOfEight,parts=octant',
'*OneOfEight,parts=octant_up',
'*OneOfEight,parts=3mid',
'*OneOfEight,parts=3side',
'*OneOfEight,parts=wedge',
'*HTree',
);
# expand arg "all" to full list
@ARGV = map {$_ eq 'all' ? @all_classes : $_} @ARGV;
my $separator = '';
foreach my $class (@ARGV) {
print $separator;
$separator = "\n";
print_class ($class);
}
sub print_class {
my ($name) = @_;
# secret leading "*Foo" means print if available
my $if_available = ($name =~ s/^\*//);
my $class = $name;
unless ($class =~ /::/) {
$class = "Math::PlanePath::$class";
}
($class, my @parameters) = split /\s*,\s*/, $class;
$class =~ /^[a-z_][:a-z_0-9]*$/i or die "Bad class name: $class";
if (! eval "require $class") {
if ($if_available) {
next;
} else {
die $@;
}
}
@parameters = map { /(.*?)=(.*)/ or die "Missing value for parameter \"$_\"";
$1,$2 } @parameters;
my %rows;
my $x_min = 0;
my $x_max = 0;
my $y_min = 0;
my $y_max = 0;
my $cellwidth = 1;
my $path = $class->new (width => POSIX::ceil($width / 4),
height => POSIX::ceil($height / 2),
@parameters);
my $x_limit_lo;
my $x_limit_hi;
if ($path->x_negative) {
my $w_cells = int ($width / $cellwidth);
my $half = int(($w_cells - 1) / 2);
$x_limit_lo = -$half;
$x_limit_hi = +$half;
} else {
my $w_cells = int ($width / $cellwidth);
$x_limit_lo = 0;
$x_limit_hi = $w_cells - 1;
}
my $y_limit_lo = 0;
my $y_limit_hi = $height-1;
if ($path->y_negative) {
my $half = int(($height-1)/2);
$y_limit_lo = -$half;
$y_limit_hi = +$half;
}
my $n_start = $path->n_start;
my $n = $n_start;
for ($n = $n_start; $n <= 999; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
# stretch these out for better resolution
if ($class =~ /Sacks/) { $x *= 1.5; $y *= 2; }
if ($class =~ /Archimedean/) { $x *= 2; $y *= 3; }
if ($class =~ /Theodorus|MultipleRings/) { $x *= 2; $y *= 2; }
if ($class =~ /Vogel/) { $x *= 2; $y *= 3.5; }
# nearest integers
$x = POSIX::floor ($x + 0.5);
$y = POSIX::floor ($y + 0.5);
my $cell = $rows{$x}{$y};
if (defined $cell) { $cell .= ','; }
$cell .= $n;
my $new_cellwidth = max ($cellwidth, length($cell) + 1);
my $new_x_limit_lo;
my $new_x_limit_hi;
if ($path->x_negative) {
my $w_cells = int ($width / $new_cellwidth);
my $half = int(($w_cells - 1) / 2);
$new_x_limit_lo = -$half;
$new_x_limit_hi = +$half;
} else {
my $w_cells = int ($width / $new_cellwidth);
$new_x_limit_lo = 0;
$new_x_limit_hi = $w_cells - 1;
}
my $new_x_min = min($x_min, $x);
my $new_x_max = max($x_max, $x);
my $new_y_min = min($y_min, $y);
my $new_y_max = max($y_max, $y);
if ($new_x_min < $new_x_limit_lo
|| $new_x_max > $new_x_limit_hi
|| $new_y_min < $y_limit_lo
|| $new_y_max > $y_limit_hi) {
last;
}
$rows{$x}{$y} = $cell;
$cellwidth = $new_cellwidth;
$x_limit_lo = $new_x_limit_lo;
$x_limit_hi = $new_x_limit_hi;
$x_min = $new_x_min;
$x_max = $new_x_max;
$y_min = $new_y_min;
$y_max = $new_y_max;
}
$n--; # the last N actually plotted
print "$name N=$n_start to N=$n\n\n";
foreach my $y (reverse $y_min .. $y_max) {
foreach my $x ($x_limit_lo .. $x_limit_hi) {
my $cell = $rows{$x}{$y};
if (! defined $cell) { $cell = ''; }
printf ('%*s', $cellwidth, $cell);
}
print "\n";
}
}
exit 0;
Math-PlanePath-113/devel/ 0002755 0001750 0001750 00000000000 12255673733 013015 5 ustar gg gg Math-PlanePath-113/devel/r5.pl 0000644 0001750 0001750 00000004703 11507022742 013665 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX ();
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
my $width = 79;
my $height = 23;
my @turn_right = (0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0);
sub xturn_right {
my ($n) = @_;
return $turn_right[$n-1];
}
sub turn_right {
my ($n) = @_;
while (($n % 5) == 0) {
$n = int($n/5);
}
return ($n % 5) > 2;
}
{
my %rows;
my $x_min = 0;
my $x_max = 0;
my $y_min = 0;
my $y_max = 0;
my $cellwidth = 1;
my $xd = 1;
my $yd = 0;
my $x = 0;
my $y = 0;
my $n = 1;
foreach my $n (1 .. 500) {
$x += $xd;
$y += $yd;
my $cell = $rows{$x}{$y};
if ($cell) { $cell .= '/'; }
$cell .= $n;
$rows{$x}{$y} = $cell;
$cellwidth = max ($cellwidth, length($cell)+1);
### draw: "$x,$y $cell"
$x_min = min ($x_min, $x);
$x_max = max ($x_max, $x);
$y_min = min ($y_min, $y);
$y_max = max ($y_max, $y);
my $turn_right = turn_right($n) // last;
if ($turn_right) {
### right: "$xd,$yd -> $yd,@{[-$xd]}"
($xd,$yd) = ($yd,-$xd);
} else {
### left: "$xd,$yd -> @{[-$yd]},$xd"
($xd,$yd) = (-$yd,$xd);
}
}
### $x_min
### $x_max
### $y_min
### $y_max
foreach my $y (reverse $y_min .. $y_max) {
foreach my $x ($x_min .. $x_max) {
printf ('%*s', $cellwidth, $rows{$x}{$y} || '');
}
print "\n";
}
exit 0;
}
{
foreach my $n (1 .. 50) {
print turn($n),",";
}
print "\n";
exit 0;
}
Math-PlanePath-113/devel/sierpinski-arrowhead.pl 0000644 0001750 0001750 00000010077 12021370606 017467 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::SierpinskiArrowhead;
# uncomment this to run the ### lines
use Smart::Comments;
{
# turn sequence
require Math::NumSeq::PlanePathTurn;
require Math::BaseCnv;
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'SierpinskiArrowhead',
turn_type => 'Left');
foreach (1 .. 400) {
my ($i, $value) = $seq->next;
my $i3 = Math::BaseCnv::cnv($i,10,3);
my $calc = calc_turnleft($i);
print "$i $i3 $value $calc\n";
}
sub calc_turnleft { # not working
my ($n) = @_;
my $ret = 1;
my $flip = 0;
while ($n && ($n % 9) == 0) {
$n = int($n/9);
}
if ($n) {
my $digit = $n % 9;
my $flip = ($digit == 0
|| $digit == 1 # 01
# || $digit == 3 # 10
|| $digit == 5 # 12
|| $digit == 6 # 20
|| $digit == 7 # 21
);
$ret ^= $flip;
$n = int($n/9);
}
while ($n) {
my $digit = $n % 9;
my $flip = ($digit == 1 # 01
|| $digit == 3 # 10
|| $digit == 5 # 12
|| $digit == 7 # 21
);
$ret ^= $flip;
$n = int($n/9);
}
return $ret;
}
sub WORKING__calc_turnleft { # works
my ($n) = @_;
my $ret = 1;
while ($n && ($n % 3) == 0) {
$ret ^= 1; # flip for trailing 0s
$n = int($n/3);
}
$n = int($n/3);
while ($n) {
if (($n % 3) == 1) { # flip for all 1s
$ret ^= 1;
}
$n = int($n/3);
}
return $ret;
}
sub count_digits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count++;
$n = int($n/3);
}
return $count;
}
sub count_1_digits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += (($n % 3) == 1);
$n = int($n/3);
}
return $count;
}
exit 0;
}
{
# direction sequence
require Math::NumSeq::PlanePathDelta;
require Math::BaseCnv;
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => 'SierpinskiArrowhead',
delta_type => 'TDir6');
foreach (1 .. 3**4+1) {
my ($i, $value) = $seq->next;
# $value %= 6;
my $i3 = Math::BaseCnv::cnv($i,10,3);
my $calc = calc_dir6($i);
print "$i $i3 $value $calc\n";
}
sub calc_dir6 { # works
my ($n) = @_;
my $dir = 1;
while ($n) {
if (($n % 9) == 0) {
} elsif (($n % 9) == 1) {
$dir = 3 - $dir;
} elsif (($n % 9) == 2) {
$dir = $dir + 2;
} elsif (($n % 9) == 3) {
$dir = 3 - $dir;
} elsif (($n % 9) == 4) {
} elsif (($n % 9) == 5) {
$dir = 1 - $dir;
} elsif (($n % 9) == 6) {
$dir = $dir - 2;
} elsif (($n % 9) == 7) {
$dir = 1 - $dir;
} elsif (($n % 9) == 8) {
}
$n = int($n/9);
}
return $dir % 6;
}
sub Xcalc_dir6 { # works
my ($n) = @_;
my $dir = 1;
while ($n) {
if (($n % 3) == 0) {
}
if (($n % 3) == 1) {
# mirror
$dir = 3 - $dir;
}
if (($n % 3) == 2) {
$dir = $dir + 2;
}
$n = int($n/3);
if (($n % 3) == 0) {
}
if (($n % 3) == 1) {
# mirror
$dir = 3 - $dir;
}
if (($n % 3) == 2) {
$dir = $dir - 2;
}
$n = int($n/3);
}
return $dir % 6;
}
exit 0;
}
Math-PlanePath-113/devel/koch-squareflakes.pl 0000644 0001750 0001750 00000007160 12167214734 016756 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::PlanePath::KochSquareflakes;
# horiz: 1, 4, 14, 48, 164, 560, 1912, 6528, 22288, 76096, 259808, 887040
# A007070 a(n+1) = 4*a(n) - 2*a(n-1), starting 1,4
#
# diag: 1, 3, 10, 34, 116, 396, 1352, 4616, 15760, 53808, 183712, 627232
# A007052 a(n+1) = 4*a(n) - 2*a(n-1), starting 1,3
#
{
# max extents of a single side
# A007070 max horiz dist from ring start pos 4,14,48,164 side width
# A206374 N of the max position 2,9,37,149 corner
# A003480 X of the max position 2,7,24,82 last
# A007052 max vert dist from ring start pos 3,10,34,116 height
# A072261 N of the max Y position 7,29,117,469 Y axis
# A007052 Y of the max position 3,10,34,116
my $path = Math::PlanePath::KochSquareflakes->new;
my @values;
my $coord = 1;
foreach my $level (1 .. 8) {
my $nstart = (4**($level+1) - 1) / 3;
my $nend = $nstart + 4**$level;
my @start = $path->n_to_xy($nstart);
my $max_offset = 0;
my $max_offset_n = $nstart;
my $max_offset_c = $start[$coord];
foreach my $n ($nstart .. $nend) {
my @this = $path->n_to_xy($n);
my $offset = abs ($this[$coord] - $start[$coord]);
if ($offset > $max_offset) {
$max_offset = $offset;
$max_offset_n = $n;
$max_offset_c = $this[$coord];
}
}
push @values, $max_offset;
print "level $level start=$start[$coord] max offset $max_offset at N=$max_offset_n (of $nstart to $nend) Y=$max_offset_c\n";
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
}
{
# X or Y coordinate of first point of ring
# X or Y coord: 1, 2,7,24,82,280,
# A003480 1,2,7 OFFSET=0
# A020727 2,7
#
# cf A006012 same recurrence, start 1,2
my $path = Math::PlanePath::KochSquareflakes->new;
my @values;
foreach my $level (1 .. 12) {
my $nstart = (4**($level+1) - 1) / 3;
my ($x,$y) = $path->n_to_xy($nstart);
push @values, -$y;
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
}
{
# Xstart power
# Xstart = b^level
# b = Xstart^(1/level)
#
# D = P^2-4Q = 4^2-4*-2 = 24
# sqrt(24) = 4.898979485566356196394568149
#
my $path = Math::PlanePath::KochSquareflakes->new;
my $prev = 1;
foreach my $level (1 .. 12) {
my $nstart = (4**($level+1) - 1) / 3;
my ($xstart,$ystart) = $path->n_to_xy($nstart);
$xstart = -$xstart;
my $f = $xstart / $prev;
# my $b = $xstart ** (1/($level+1));
print "level=$level xstart=$xstart f=$f\n";
$prev = $xstart;
}
print "\n";
exit 0;
}
{
my @horiz = (1);
my @diag = (1);
foreach my $i (0 .. 10) {
$horiz[$i+1] = 2*$horiz[$i] + 2*$diag[$i];
$diag[$i+1] = $horiz[$i] + 2*$diag[$i];
$i++;
}
print "horiz: ",join(', ',@horiz),"\n";
print "diag: ",join(', ',@diag),"\n";
exit 0;
}
Math-PlanePath-113/devel/dragon-numbers.pl 0000644 0001750 0001750 00000004013 11663113313 016252 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX ();
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
my $width = 79;
my $height = 23;
sub turn_right {
my ($n) = @_;
until ($n & 1) {
$n >>= 1;
}
return (($n >> 1) & 1) ^ 1;
}
{
my %rows;
my $x_min = 0;
my $x_max = 0;
my $y_min = 0;
my $y_max = 0;
my $cellwidth = 1;
my $xd = 1;
my $yd = 0;
my $x = 0;
my $y = 0;
my $n = 1;
foreach my $n (1 .. 500) {
$x += $xd;
$y += $yd;
my $cell = $rows{$x}{$y};
if ($cell) { $cell .= '/'; }
$cell .= $n;
$rows{$x}{$y} = $cell;
$cellwidth = max ($cellwidth, length($cell)+1);
### draw: "$x,$y $cell"
$x_min = min ($x_min, $x);
$x_max = max ($x_max, $x);
$y_min = min ($y_min, $y);
$y_max = max ($y_max, $y);
if (turn_right($n)) {
### right: "$xd,$yd -> $yd,@{[-$xd]}"
($xd,$yd) = ($yd,-$xd);
} else {
### left: "$xd,$yd -> @{[-$yd]},$xd"
($xd,$yd) = (-$yd,$xd);
}
}
### $x_min
### $x_max
### $y_min
### $y_max
foreach my $y (reverse $y_min .. $y_max) {
foreach my $x ($x_min .. $x_max) {
printf ('%*s', $cellwidth, $rows{$x}{$y} || '');
}
print "\n";
}
exit 0;
}
{
foreach my $n (1 .. 50) {
print turn($n),",";
}
print "\n";
exit 0;
}
Math-PlanePath-113/devel/cubic-base.pl 0000644 0001750 0001750 00000005342 12003406621 015326 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::MoreUtils;
use POSIX 'floor';
use Math::Libm 'M_PI', 'hypot';
use List::Util 'min', 'max';
use Math::BaseCnv 'cnv';
use lib 'xt';
# uncomment this to run the ### lines
use Smart::Comments;
{
# smallest hypot in each level
require Math::PlanePath::CubicBase;
require Math::NumSeq::PlanePathDelta;
my $tdir6_func = \&Math::NumSeq::PlanePathDelta::_delta_func_TDir6;
my $radix = 2;
my $path = Math::PlanePath::CubicBase->new (radix => $radix);
foreach my $level (1 .. 30) {
my $n_lo = $radix ** ($level-1);
my $n_hi = $radix ** $level - 1;
my $n = $n_lo;
my $min_h = $path->n_to_rsquared($n);
my @min_n = ($n);
for ($n++; $n < $n_hi; $n++) {
my $h = $path->n_to_rsquared($n);
if ($h < $min_h) {
@min_n = ($n);
$min_h = $h;
} elsif ($h == $min_h) {
push @min_n, $n;
}
}
print "level=$level\n";
# print " n=${n_lo}to$n_hi\n";
print " min_h=$min_h\n";
foreach my $n (@min_n) {
my $nr = cnv($n,10,$radix);
my ($x,$y) = $path->n_to_xy($n);
my $xr = cnv($x,10,$radix);
my $yr = cnv($y,10,$radix);
my $tdir6 = $tdir6_func->(0,0,$x,$y);
print " n=$n $nr xy=$x,$y $xr,$yr tdir6=$tdir6 \n";
}
}
exit 0;
sub path_n_to_trsquared {
my ($path,$n) = @_;
my ($x,$y) = $path->n_to_xy($n);
return $x*$x+3*$y*$y;
}
}
{
# Dir4 maximum
require Math::PlanePath::CubicBase;
require Math::NumSeq::PlanePathDelta;
require Math::BigInt;
my $path = Math::PlanePath::CubicBase->new;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => 'CubicBase',
delta_type => 'Dir4');
my $dir4_max = 0;
foreach my $level (0 .. 600) {
my $n = Math::BigInt->new(2)**$level - 1;
my $dir4 = $seq->ith($n);
if (1 || $dir4 > $dir4_max) {
$dir4_max = $dir4;
my ($dx,$dy) = $path->n_to_dxdy($n);
printf "%3d %2b,\n %2b %8.6f\n", $n, abs($dx),abs($dy), $dir4;
}
}
exit 0;
}
Math-PlanePath-113/devel/pixel-rings.pl 0000644 0001750 0001750 00000015146 11667347222 015615 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX ();
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
{
# vs spectrum
require Image::Base::Text;
my $prev = 0;
my $diff_total = 0;
my $diff_count = 0;
my $prev_count = 0;
my $prev_sq = 0;
foreach my $r (1 .. 6000) {
my $count = image_count($r) / 4;
my $dcount = $count - $prev_count - 1;
my $xfrac = (1 + sqrt(8*($r+0)**2-1))/4;
# my $x = (2 + sqrt(8*($r+0)**2-4))/4;
my $y = int($xfrac+.5);
my $x = int($xfrac);
my $extra = (($y-1)**2 + ($y+.5)**2) < $r*$r;
$extra = ($x==$y); # && (($x^$y^1)&1);
my $sq = $y + $y-1 + $extra;
my $dsq = $sq - $prev_sq;
my $star = ($dsq != $dcount ? "***" : "");
# printf "%2d dc=%3d dsq=%4.2f %s\n", $r, $dcount,$dsq, $star;
$star = (int($sq) != $count ? "***" : "");
printf "%2d c=%3d sq=%4.2f x=%4.2f,y=$y %s\n", $r, $count,$sq,$x, $star;
$prev_count = $count;
$prev_sq = $sq;
}
exit 0;
sub floor_half {
my ($n) = @_;
return int(2*$n)/2;
}
}
{
my $r = 5;
my $w = 2*$r+1;
require Image::Base::Text;
my $image = Image::Base::Text->new (-width => $w,
-height => $w);
$image->ellipse (0,0, $w-1,$w-1, 'x');
my $str = $image->save_string;
print $str;
exit 0;
}
{
# wider ellipse() overlaps, near centre mostly
my %image_coords;
my $offset = 100;
my $i;
{
package MyImageCoords;
require Image::Base;
use vars '@ISA';
@ISA = ('Image::Base');
sub new {
my $class = shift;
return bless {@_}, $class;
}
sub xy {
my ($self, $x, $y, $colour) = @_;
my $key = "$x,$y";
if ($image_coords{$key}) {
$image_coords{$key} .= ',';
}
$image_coords{$key} .= $i;
}
}
my $width = 500;
my $height = 494;
my $image = MyImageCoords->new (-width => $width, -height => $height);
for ($i = 0; $i < min($width,$height)/2; $i++) {
$image->ellipse ($i,$i, $width-1-$i,$height-1-$i, $i % 10);
}
foreach my $coord (keys %image_coords) {
if ($image_coords{$coord} =~ /,/) {
print "$coord i=$image_coords{$coord}\n";
}
}
exit 0;
}
{
# wider ellipse()
require Image::Base::Text;
my $width = 40;
my $height = 10;
my $image = Image::Base::Text->new (-width => $width, -height => $height);
for (my $i = 0; $i < min($width,$height)/2; $i++) {
$image->ellipse ($i,$i, $width-1-$i,$height-1-$i, $i % 10);
}
$image->save('/dev/stdout');
exit 0;
}
{
# average diff step 4*sqrt(2)
require Image::Base::Text;
my $prev = 0;
my $diff_total = 0;
my $diff_count = 0;
foreach my $r (1 .. 1000) {
my $count = image_count($r);
my $diff = $count - $prev;
# printf "%2d %3d %2d\n", $r, $count, $diff;
$prev = $count;
$diff_total += $diff;
$diff_count++;
}
my $avg = $diff_total/$diff_count;
my $sqavg = $avg*$avg;
print "diff average $avg squared $sqavg\n";
exit 0;
}
{
# vs int(sqrt(2))
require Image::Base::Text;
my $prev = 0;
my $diff_total = 0;
my $diff_count = 0;
my $prev_count = 0;
my $prev_sq = 0;
foreach my $r (1 .. 300) {
my $count = image_count($r) / 4;
my $dcount = $count - $prev_count - 1;
my $sq = int(sqrt(2) * ($r+3));
my $dsq = $sq - $prev_sq - 1;
my $star = ($dsq != $dcount ? "***" : "");
printf "%2d %3d %3d %s\n", $r, $dcount,$dsq, $star;
$prev_count = $count;
$prev_sq = $sq;
}
exit 0;
}
{
# vs int(sqrt(2))
my $prev = 0;
my $diff_total = 0;
my $diff_count = 0;
foreach my $r (1 .. 500) {
my $count = image_count($r);
my $sq = 4*int(sqrt(2) * ($r+1));
my $star = ($sq != $count ? "***" : "");
printf "%2d %3d %3d %s\n", $r, $count,$sq, $star;
}
exit 0;
}
my $width = 79;
my $height = 23;
my @rows;
my @x;
my @y;
foreach my $r (0 .. 39) {
my $rr = $r * $r;
# E(x,y) = x^2*r^2 + y^2*r^2 - r^2*r^2
#
# Initially,
# d1 = E(x-1/2,y+1)
# = (x-1/2)^2*r^2 + (y+1)^2*r^2 - r^2*r^2
# which for x=r,y=0 is
# = r^2 - r^2*r + r^2/4
# = (r + 5/4) * r^2
#
my $x = $r;
my $y = 0;
my $d = ($x-.5)**2 * $rr + ($y+1)**2 * $rr - $rr*$rr;
my $count = 0;
while ($x >= $y) {
### at: "$x,$y"
### assert: $d == ($x-.5)**2 * $rr + ($y+1)**2 * $rr - $rr*$rr
push @x, $x;
push @y, $y;
$rows[$y]->[$x] = ($r%10);
$count++;
if( $d < 0 ) {
$d += $rr * (2*$y + 3);
++$y;
}
else {
$d += $rr * (2*$y - 2*$x + 5);
++$y;
--$x;
}
}
my $c = int (2*3.14159*$r/8 + .5);
printf "%2d %2d %2d %s\n", $r, $count, $c, ($count!=$c ? "**" : "");
}
foreach my $row (reverse @rows) {
if ($row) {
foreach my $char (@$row) {
print ' ', $char // ' ';
}
}
print "\n";
}
{
require Math::PlanePath::PixelRings;
my $path = Math::PlanePath::PixelRings->new (wider => 0,
# step => 0,
);
### range: $path->rect_to_n_range (0,0, 0,0)
exit 0;
}
{
# search OEIS
require Image::Base::Text;
my @count4;
my @count;
my @diffs4;
my @diffs;
my @diffs0;
my $prev_count = 0;
foreach my $r (1 .. 50) {
my $count = image_count($r);
push @count4, $count;
push @count, $count/4;
my $diff = $count - $prev_count;
push @diffs4, $diff;
push @diffs, $diff/4;
push @diffs0, $diff/4 - 1;
$prev_count = $count;
}
print "count4: ", join(',', @count4), "\n";
print "count: ", join(',', @count), "\n";
print "diffs4: ", join(',', @diffs4), "\n";
print "diffs: ", join(',', @diffs), "\n";
print "diffs0: ", join(',', @diffs0), "\n";
exit 0;
}
sub image_count {
my ($r) = @_;
my $w = 2*$r+1;
require Image::Base::Text;
my $image = Image::Base::Text->new (-width => $w,
-height => $w);
$image->ellipse (0,0, $w-1,$w-1, 'x');
my $str = $image->save_string;
my $count = ($str =~ tr/x/x/);
return $count;
}
Math-PlanePath-113/devel/fibonacci-word.logo 0000644 0001750 0001750 00000002701 12041163344 016544 0 ustar gg gg #!/usr/bin/ucblogo
;; Copyright 2012 Kevin Ryde
;;
;; This file is part of Math-PlanePath.
;;
;; Math-PlanePath 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, or (at your option) any later
;; version.
;;
;; Math-PlanePath 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 Math-PlanePath. If not, see .
;; hexagons overlapping much but slowly expanding
to fibbinary.next :n
localmake "filled bitor :n (lshift :n -1)
localmake "mask lshift (bitxor :filled (:filled + 1)) -1
output (bitor :n :mask) + 1
end
; to print.binary :n
; do.while [
; type bitand :n 1
; make "n lshift :n -1
; ] [:n <> 0]
; print "
; end
; make "n 0
; for [i 0 21 1] [
; print "n
; print :n
; print.binary :n
; make "n fibbinary.next :n
; ]
to fib.hex :steps
; right 90
; left 45
; penup
; back 300
; right 90
; pendown
localmake "step.len 10
localmake "n 0
for [i 0 :steps 1] [
forward :step.len
if (bitand :n 1)=0 [left 60] [right 60]
make "n fibbinary.next :n
]
end
fib.hex 210000 Math-PlanePath-113/devel/theodorus.pl 0000644 0001750 0001750 00000025627 12040145574 015365 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX 'floor', 'fmod';
use Math::Trig 'pi', 'atan';
use Math::BigFloat try => 'GMP';
use Math::Libm 'hypot';
use Math::PlanePath::TheodorusSpiral;
use Smart::Comments;
{
# Euler summation
# kparse_from_string("TREE_a * (TREE_b / TREE_c)");
# my $pattern = Math::Symbolic::Custom::Pattern->new($formula);
use Math::Symbolic::Custom::Transformation;
my $trafo = Math::Symbolic::Custom::Transformation::Group->new
(',',
'TREE_a * (TREE_b / TREE_c)' => '(TREE_a * TREE_b) / TREE_c',
'TREE_a * (TREE_b + TREE_c)' => 'TREE_a * TREE_b + TREE_a * TREE_c',
'(TREE_b + TREE_c) * TREE_a' => 'TREE_b * TREE_a + TREE_c * TREE_a',
# '(TREE_a / TREE_b) / TREE_c' => 'TREE_a / (TREE_b * TREE_c)',
'(TREE_a / TREE_b) / (TREE_c / TREE_d)'
=> '(TREE_a * TREE_d) / (TREE_b * TREE_c)',
'1 - TREE_a / TREE_b' => '(TREE_b - TREE_a) / TREE_b',
'TREE_a / TREE_b + TREE_c' => '(TREE_a + TREE_b * TREE_c) / TREE_b',
'(TREE_a / TREE_b) * TREE_c' => '(TREE_a * TREE_c) / TREE_b',
'TREE_a - (TREE_b + TREE_c)' => 'TREE_a - TREE_b - TREE_c',
'(TREE_a - TREE_b) - TREE_c' => 'TREE_a - TREE_b - TREE_c',
);
sub simplify {
my $tree = shift;
### simplify(): "$tree"
### traf: ($trafo->apply_recursive($tree)//'').''
return $trafo->apply_recursive($tree) || $tree;
# if (my $m = $pattern->match($tree)) {
# $m = $m->{'trees'};
# ### trees: $m
# ### return: ($m->{'a'} * $m->{'b'}) / $m->{'c'}
# return ($m->{'a'} * $m->{'b'}) / $m->{'c'};
# } else {
# ### no match
# return $tree;
# }
}
__PACKAGE__->register();
}
require Math::Symbolic;
require Math::Symbolic::Derivative;
{
my $t = Math::Symbolic->parse_from_string('1/(x^2+1)');
$t = Math::Symbolic::Derivative::total_derivative($t, 'x');
$t = $t->simplify;
print "$t\n";
exit 0;
}
{
my $a = Math::Symbolic->parse_from_string(
'(x+y)/(1-x*y)'
);
my $z = Math::Symbolic->parse_from_string(
'z'
);
my $t = ($a + $z) / (1 - $a*$z);
$t = $t->simplify;
print $t;
exit 0;
}
}
{
my $path = Math::PlanePath::TheodorusSpiral->new;
my $prev_x = 0;
my $prev_y = 0;
#for (my $n = 10; $n < 100000000; $n = int($n * 1.2)) {
foreach my $n (2000, 2010, 2020, 2010, 2000, 2010, 2000, 2010) {
my ($x,$y) = $path->n_to_xy($n);
my $rsq = $x*$x+$y*$y;
my $dx = $x - $prev_x;
my $dy = $y - $prev_y;
my $dxy_dist = hypot($dx,$dy);
printf "%d %.2f,%.2f %.2f %.4f\n", $n, $x,$y, $rsq, $dxy_dist;
($prev_x, $prev_y) = ($x,$y);
}
exit 0;
}
sub integral {
my ($x) = @_;
print "log ", log(1+$x*$x), " at x=$x\n";
return $x * atan($x) - 0.5 * log (1 + $x*$x);
}
print "integral 0 = ", integral(0), "\n";
print "integral 1 = ", integral(1)/(2*pi()), "\n";
print "atan 1 = ", atan(1)/(2*pi()), "\n";
sub est {
my ($n) = @_;
my $k = $n-1;
if ($k == 0) { return 0; }
my $K = 2.1577829966;
my $root = sqrt($k);
my $a = 2*pi()*pi();
my $radians;
$radians = integral(1/$root); # - integral(0);
# $radians = ($k+1)*atan(1/$root) + $root - 1/($root*$k);
return $radians / (2*pi());
# $radians = 2*$root;
# return $radians / (2*pi());
#
# $radians = $root - atan($root) + $k*atan(1/$root);
# return $radians / (2*pi());
#
# return $k / $a; # revolutions
# return $k / pi();
#
# return 2*$root / $a;
# $radians = 2*sqrt($k+1) + $K + 1/(6*sqrt($k+1)); # plus O(n^(-3/2))
# return 0.5 * $a * ($k * sqrt(1+$k*$k) + log($k + sqrt(1+$k*$k))) / $k;
# return $root + ($k+1)*atan(1/$root);
}
print "est 1 = ", est(1), "\n";
print "est 2 = ", est(2), "\n";
{
require Math::Polynomial;
open OUT, '>', '/tmp/theodorus.data' or die;
my @n;
my @theta;
my $total = 0;
foreach my $n (2 .. 120) {
my $inc = Math::Trig::atan(1/sqrt($n-1)) / (2*pi()); # revs
$total += $inc;
my $est = est($n);
my $diff = $total - $est;
# $diff = 1/$diff;
if ($n > 50) {
push @n, $n-51;
push @theta, $diff;
print OUT "$n $diff\n";
}
print "$n $inc $total $est $diff\n";
}
print "\n";
Math::BigFloat->accuracy(500);
my $p = Math::Polynomial->new; # (Math::BigFloat->new(0));
$p = $p->interpolate(\@n, \@theta);
foreach my $i (0 .. $p->degree) {
print "$i ",$p->coeff($i),"\n";
}
# $p->string_config({ fold_sign => 1,
# variable => 'n' });
# print "theta = $p\n";
close OUT or die;
system "xterm -e 'gnuplot = $next) {
$next++;
my $diff = $n - $prev_n;
my $diff_diff = $diff - $prev_diff;
$total_diff_diff += $diff_diff;
$count_diff_diff++;
print "$n +$diff +$diff_diff $total\n";
if ($next >= 1000) {
last;
}
$prev_n = $n;
$prev_diff = $diff;
}
}
my $avg = $total_diff_diff / $count_diff_diff;
print "average $avg\n";
print "\n";
exit 0;
}
{
my $c2 = 2.15778;
my $t1 = 1.8600250;
my $t2 = 0.43916457;
my $z32 = 2.6123753486;
my $tn1 = 2*$t1 - 2*$t2 - $z32;
my $n = 1;
my $x = 1;
my $y = 0;
while ($n < 10000) {
my $r = sqrt($n); # before increment
($x, $y) = ($x - $y/$r, $y + $x/$r);
$n++;
$r = sqrt($n); # after increment
my $theta = atan2($y,$x);
if ($theta < 0) { $theta += 2*pi(); }
my $root;
$root = 2*sqrt($n) - $c2;
# $root += .01/$r;
# $root = -atan(sqrt($n)) + $n*atan(1/sqrt($n)) + sqrt($n);
# $root = atan(1/sqrt($n)) - pi()/2 + $n*atan(1/sqrt($n)) + sqrt($n);
$root = 2*sqrt($n)
+ 1/sqrt($n)
- $c2
# - 1/($n*sqrt($n))/3
# + 1/($n*$n*sqrt($n))/5
# - 1/($n*$n*sqrt($n))/7
# + 1/($n*$n*$n*sqrt($n))/9
;
# $root = -pi()/4 + Arctan($r);
# foreach my $k (2 .. 1000000) {
# $root += atan(1/sqrt($k)) - atan(1/sqrt($k + $r*$r - 1));
# # $root += atan( ($r*$r - 1) / ( ($k + $r*$r)*sqrt($k) + ($k+1)*sqrt($k+$r*$r-1)));
# }
# $root = -pi()/2 + Arctan($r) + $t1 *$r*$r/2 + ($tn1 - $t1)*$r**2/8;
$root = fmod ($root, 2*pi());
my $d = $root - $theta;
$d = fmod ($d + pi(), 2*pi()) - pi();
# printf "%10.6f %10.6f %23.20f\n", $theta, $root, $d;
printf "%23.20f\n", $d;
}
exit 0;
}
{
my $t1 = 0;
foreach my $k (1 .. 100) {
$t1 += 1 / (sqrt($k) * ($k+1));
printf "%10.6f\n", $t1;
}
exit 0;
}
sub Arctan {
my ($r) = @_;
return pi()/2 - atan(1/$r);
}
{
Math::BigFloat->accuracy(200);
my $bx = Math::BigFloat->new(1);
my $by = Math::BigFloat->new(0);
my $x = 1;
my $y = 0;
my $n = 1;
my @n = ($n);
my @x = ($x);
my @y = ($y);
my $count = 0;
my $prev_n = 0;
my $prev_d = 0;
my @dd;
while ($n++ < 10000000) {
my $r = hypot($x,$y);
my $py = $y;
($x, $y) = ($x - $y/$r, $y + $x/$r);
if ($py < 0 && $y >= 0) {
my $d = $n-$prev_n;
my $dd = $d-$prev_d;
push @dd, $dd;
printf "%5d +%4d +%3d %7.3f %10.6f %10.6f\n",
$n,
$d,
$dd,
# (sqrt($n)-1.07)/pi(),
sqrt($n),
$x, $y;
$prev_n = $n;
$prev_d = $d;
if (++$count >= 10) {
push @n, $n;
push @x, $x;
push @y, $y;
$count = 0;
}
}
}
print "average dd ", List::Util::sum(@dd)/scalar(@dd),"\n";
# require Data::Dumper;
# print Data::Dumper->new([\@n],['n'])->Indent(1)->Dump;
# print Data::Dumper->new([\@x],['x'])->Indent(1)->Dump;
# print Data::Dumper->new([\@y],['y'])->Indent(1)->Dump;
# require Math::Polynomial;
# my $p = Math::Polynomial->new(0);
# $p = $p->interpolate([ 1 .. @nc ], \@nc);
# $p->string_config({ fold_sign => 1,
# variable => 'd' });
# print "N = $p\n";
exit 0;
}
{
Math::BigFloat->accuracy(200);
my $bx = Math::BigFloat->new(1);
my $by = Math::BigFloat->new(0);
my $x = 1;
my $y = 0;
my $n = 1;
while ($n++ < 10000) {
my $r = hypot($x,$y);
($x, $y) = ($x - $y/$r, $y + $x/$r);
my $br = sqrt($bx*$bx + $by*$by);
($bx, $by) = ($bx - $by/$br, $by + $bx/$br);
}
my $ex = "$bx" + 0;
my $ey = "$by" + 0;
printf "%10.6f %10.6f %23.20f\n", $ex, $x, $ex - $x;
exit 0;
}
Math-PlanePath-113/devel/exe-atan2.c 0000644 0001750 0001750 00000003472 12005653477 014745 0 ustar gg gg /* Copyright 2011, 2012 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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 Math-PlanePath. If not, see .
*/
#include
#include
#include
#include
void
dump (double d)
{
union { double d; unsigned char byte[8]; } u;
u.d = d;
printf ("%02X %02X %02X %02X %02X %02X %02X %02X\n",
u.byte[0], u.byte[1], u.byte[2], u.byte[3],
u.byte[4], u.byte[5], u.byte[6], u.byte[7]);
}
static const double double_ulong_max_plus_1
= ((double) ((ULONG_MAX >> 1)+1)) * 2.0;
static const double double_ull_max_plus_1
= ((double) ((ULLONG_MAX >> 1)+1)) * 2.0;
int
main (void)
{
volatile double zero = 0;
volatile double negzero = -zero;
dump (zero);
dump (negzero);
printf ("%la %la\n", zero,negzero);
printf ("%la\n", atan2(zero,zero));
printf ("%la\n", atan2(negzero,zero));
printf ("\n");
printf ("%la\n", atan2(zero,negzero));
printf ("%la\n", atan2(negzero,negzero));
printf ("\n");
printf ("ulong %la ", double_ulong_max_plus_1);
dump (double_ulong_max_plus_1);
printf (" %lf\n", double_ulong_max_plus_1);
printf ("ull %la ", double_ull_max_plus_1);
dump (double_ull_max_plus_1);
printf (" %lf\n", double_ull_max_plus_1);
exit (0);
}
Math-PlanePath-113/devel/sierpinski-triangle.gnuplot 0000644 0001750 0001750 00000006636 12041164262 020404 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
#------------------------------------------------------------------------------
set xrange [0:16]; set yrange [0:16]
set key off
set samples 256
splot (int(x)&int(y))==0 ? 1 : NaN with points
pause 100
#------------------------------------------------------------------------------
triangle_x(n) = (n > 0 \
? 2*triangle_x(int(n/3)) + digit_to_x(int(n)%3) \
: 0)
triangle_y(n) = (n > 0 \
? 2*triangle_y(int(n/3)) + digit_to_y(int(n)%3) \
: 0)
digit_to_x(d) = (d==0 ? 0 : d==1 ? -1 : 1)
digit_to_y(d) = (d==0 ? 0 : 1)
# Plot the Sierpinski triangle to "level" many replications.
# trange and samples are chosen so that the parameter t runs through
# integers 0 to 3**level-1 inclusive.
#
level=6
set trange [0:3**level-1] #
set samples 3**level # making t integers
set parametric
set key off
plot triangle_x(t), triangle_y(t) with points
pause 100
#------------------------------------------------------------------------------
# 0 0 0
# 1 -1 1
# 2 1 -1
# n%3 >=
# triangle(n) = (n > 0 \
# ? 2*triangle(int(n/3)) + (int(n)%3==0 ? {0,0} \
# : int(n)%3==1 ? {-1,1} \
# : {1,1}) \
# : 0)
# level=6
# set trange [0:3**level-1]
# set samples 3**level
# set parametric
# set key off
# plot real(triangle(t)), imag(triangle(t)) with points
#
# pause 100
#
# #------------------------------------------------------------------------------
# root = cos(pi*2/3) + {0,1}*sin(pi*2/3)
#
# print root**0
# print root**1
# print root**2
#
# # triangle(n) = (n > 0 \
# # ? (1+2*triangle(int(n/3)))*root**(int(n)%3) \
# # : 0)
#
# # left = cos(pi*2/3) + {0,1}*sin(pi*2/3)
# # right = cos(pi*1/3) + {0,1}*sin(pi*1/3)
# left = {-1,1}
# right = {1,1}
#
#
# t_to_x(t,size) = int(t / size)
# t_to_y(t,size) = (int(t) % size)
#
# t_to_pyramid_x(t,size) = t_to_x(t,size) - t_to_y(t,size)
# t_to_pyramid_y(t,size) = t_to_x(t,size) + t_to_y(t,size)
#
# sierpinski_x(t,size) = \
# (t_to_x(t,size) & t_to_y(t,size) \
# ? NaN \
# : t_to_pyramid_x(t,size))
# sierpinski_y(t,size) = \
# (t_to_x(t,size) & t_to_y(t,size) \
# ? NaN \
# : t_to_pyramid_y(t,size))
#
# size=50
# set trange [0:size*size-1]
# set samples size*size
# set parametric
# set key off
# plot sierpinski_x(t,size), sierpinski_y(t,size) with points
#
# pause 100 Math-PlanePath-113/devel/sierpinski-arrowhead-stars.pl 0000644 0001750 0001750 00000002634 11612663016 020626 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use POSIX ();
use Math::PlanePath::SierpinskiArrowhead;
# uncomment this to run the ### lines
use Smart::Comments;
{
my $path = Math::PlanePath::SierpinskiArrowhead->new;
my @rows = ((' ' x 79) x 64);
foreach my $n (0 .. 3 * 3**4) {
my ($x, $y) = $path->n_to_xy ($n);
$x += 32;
substr ($rows[$y], $x,1, '*');
}
local $,="\n";
print reverse @rows;
exit 0;
}
{
my @rows = ((' ' x 64) x 32);
foreach my $p (0 .. 31) {
foreach my $q (0 .. 31) {
next if ($p & $q);
my $x = $p-$q;
my $y = $p+$q;
next if ($y >= @rows);
$x += 32;
substr ($rows[$y], $x,1, '*');
}
}
local $,="\n";
print reverse @rows;
exit 0;
}
Math-PlanePath-113/devel/quintet.pl 0000644 0001750 0001750 00000011767 11755772113 015051 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use Math::Libm 'M_PI', 'hypot';
{
require Math::PlanePath::QuintetCurve;
require Math::PlanePath::QuintetCentres;
my $f = Math::PlanePath::QuintetCurve->new (arms=>4);
my $c = Math::PlanePath::QuintetCentres->new (arms=>4);
my $width = 5;
my %saw;
my $n_end = 5**($width-1) * $f->arms_count;
foreach my $n (0 .. $n_end) {
my ($x,$y) = $f->n_to_xy($n);
my $cn = $c->xy_to_n($x,$y) // -1;
my $cr = $c->xy_to_n($x+1,$y) // -1;
my $cur = $c->xy_to_n($x+1,$y+1) // -1;
my $cu = $c->xy_to_n($x, $y+1) // -1; # <-----
my $cul = $c->xy_to_n($x-1,$y+1) // -1; # <-----
my $cl = $c->xy_to_n($x-1,$y) // -1; # <-----
my $cdl = $c->xy_to_n($x-1,$y-1) // -1;
my $cd = $c->xy_to_n($x, $y-1) // -1;
my $cdr = $c->xy_to_n($x+1,$y-1) // -1;
if ($n == $cn) { $saw{'n'} = 0; }
if ($n == $cr) { $saw{'r'} = 1; }
if ($n == $cur) { $saw{'ur'} = 2; }
if ($n == $cu) { $saw{'u'} = 3; }
if ($n == $cul) { $saw{'ul'} = 4; }
if ($n == $cl) { $saw{'l'} = 5; }
if ($n == $cdl) { $saw{'dl'} = 6; }
if ($n == $cd) { $saw{'d'} = 7; }
if ($n == $cdr) { $saw{'dr'} = 8; }
unless ($n == $cn
|| $n == $cr
|| $n == $cur
|| $n == $cu
|| $n == $cul
|| $n == $cl
|| $n == $cdl
|| $n == $cd
|| $n == $cdr) {
die "$n";
}
# print "$n5 $cn5 $ch5 $cw5 $cu5 $bad\n";
}
my $saw = join(',', sort {$saw{$a}<=>$saw{$b}} keys %saw);
print "$saw to n_end=$n_end\n";
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::QuintetCurve;
require Math::PlanePath::QuintetCentres;
my $f = Math::PlanePath::QuintetCurve->new;
my $c = Math::PlanePath::QuintetCentres->new;
my $width = 5;
my %saw;
foreach my $n (0 .. 5**($width-1)) {
my $n5 = sprintf '%*s', $width, Math::BaseCnv::cnv($n,10,5);
my ($x,$y) = $f->n_to_xy($n);
my $cn = $c->xy_to_n($x,$y) || -1;
my $cn5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cn,10,5);
my $rx = $x + 1;
my $ry = $y;
my $cr = $c->xy_to_n($rx,$ry) || -1;
my $cr5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cr,10,5);
my $urx = $x + 1;
my $ury = $y + 1;
my $cur = $c->xy_to_n($urx,$ury) || -1;
my $cur5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cur,10,5);
my $ux = $x;
my $uy = $y + 1;
my $cu = $c->xy_to_n($ux,$uy) || -1;
my $cu5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cu,10,5);
my $ulx = $x - 1;
my $uly = $y + 1;
my $cul = $c->xy_to_n($ulx,$uly) || -1;
my $cul5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cul,10,5);
my $lx = $x - 1;
my $ly = $y;
my $cl = $c->xy_to_n($lx,$ly) || -1;
my $cl5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cl,10,5);
my $dlx = $x - 1;
my $dly = $y - 1;
my $cdl = $c->xy_to_n($dlx,$dly) || -1;
my $cdl5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cdl,10,5);
my $dx = $x;
my $dy = $y - 1;
my $cd = $c->xy_to_n($dx,$dy) || -1;
my $cd5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cd,10,5);
my $drx = $x + 1;
my $dry = $y - 1;
my $cdr = $c->xy_to_n($drx,$dry) || -1;
my $cdr5 = sprintf '%*s', $width, Math::BaseCnv::cnv($cdr,10,5);
if ($n == $cn) { $saw{'n'} = 0; }
if ($n == $cr) { $saw{'r'} = 1; }
if ($n == $cur) { $saw{'ur'} = 2; }
if ($n == $cu) { $saw{'u'} = 3; }
if ($n == $cul) { $saw{'ul'} = 4; }
if ($n == $cl) { $saw{'l'} = 5; }
if ($n == $cdl) { $saw{'dl'} = 6; }
if ($n == $cd) { $saw{'d'} = 7; }
if ($n == $cdr) { $saw{'dr'} = 8; }
my $bad = ($n == $cn
|| $n == $cr
|| $n == $cur
|| $n == $cu
|| $n == $cul
|| $n == $cl
|| $n == $cdl
|| $n == $cd
|| $n == $cdr
? ''
: ' ******');
# print "$n5 $cn5 $ch5 $cw5 $cu5 $bad\n";
}
my $saw = join(',', sort {$saw{$a}<=>$saw{$b}} keys %saw);
print "$saw\n";
exit 0;
}
{
my $x = 1;
my $y = 0;
for (my $level = 1; $level < 20; $level++) {
# (x+iy)*(2+i)
($x,$y) = (2*$x - $y, $x + 2*$y);
if (abs($x) >= abs($y)) {
$x -= ($x<=>0);
} else {
$y -= ($y<=>0);
}
print "$level $x,$y\n";
}
exit 0;
}
Math-PlanePath-113/devel/r5-dragon.pl 0000644 0001750 0001750 00000020322 12000731455 015125 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::MoreUtils;
use POSIX 'floor';
use Math::Libm 'M_PI', 'hypot';
use List::Util 'min', 'max';
use lib 'devel/lib';
use lib '../iother/lib';
# uncomment this to run the ### lines
use Smart::Comments;
{
# arm xy modulus
require Math::PlanePath::R5DragonMidpoint;
my $path = Math::PlanePath::R5DragonMidpoint->new (arms => 4);
my %dxdy_to_digit;
my %seen;
for (my $n = 0; $n < 6125; $n++) {
my $digit = $n % 5;
foreach my $arm (0 .. 3) {
my ($x,$y) = $path->n_to_xy(4*$n+$arm);
my $nb = int($n/5);
my ($xb,$yb) = $path->n_to_xy(4*$nb+$arm);
# (x+iy)*(1+2i) = x-2y + 2x+y
($xb,$yb) = ($xb-2*$yb, 2*$xb+$yb);
my $dx = $xb - $x;
my $dy = $yb - $y;
my $dxdy = "$dx,$dy";
my $show = "${dxdy}[$digit]";
$seen{$x}{$y} = $show;
if ($dxdy eq '0,0') {
}
# if (defined $dxdy_to_digit{$dxdy} && $dxdy_to_digit{$dxdy} != $digit) {
# die;
# }
$dxdy_to_digit{$dxdy} = $digit;
}
}
foreach my $y (reverse -45 .. 45) {
foreach my $x (-5 .. 5) {
printf " %9s", $seen{$x}{$y}//'e'
}
print "\n";
}
### %dxdy_to_digit
exit 0;
}
{
# Midpoint xy to n
require Math::PlanePath::DragonMidpoint;
require Math::BaseCnv;
my @yx_adj_x = ([0,1,1,0],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]);
my @yx_adj_y = ([0,0,1,1],
[0,0,1,1],
[1,1,0,0],
[1,1,0,0]);
sub xy_to_n {
my ($self, $x,$y) = @_;
my $n = ($x * 0 * $y) + 0; # inherit bignum 0
my $npow = $n + 1; # inherit bignum 1
while (($x != 0 && $x != -1) || ($y != 0 && $y != 1)) {
# my $ax = ((($x+1) ^ ($y+1)) >> 1) & 1;
# my $ay = (($x^$y) >> 1) & 1;
# ### assert: $ax == - $yx_adj_x[$y%4]->[$x%4]
# ### assert: $ay == - $yx_adj_y[$y%4]->[$x%4]
my $y4 = $y % 4;
my $x4 = $x % 4;
my $ax = $yx_adj_x[$y4]->[$x4];
my $ay = $yx_adj_y[$y4]->[$x4];
### at: "$x,$y n=$n axy=$ax,$ay bit=".($ax^$ay)
if ($ax^$ay) {
$n += $npow;
}
$npow *= 2;
$x -= $ax;
$y -= $ay;
### assert: ($x+$y)%2 == 0
($x,$y) = (($x+$y)/2, # rotate -45 and divide sqrt(2)
($y-$x)/2);
}
### final: "xy=$x,$y"
my $arm;
if ($x == 0) {
if ($y) {
$arm = 1;
### flip ...
$n = $npow-1-$n;
} else { # $y == 1
$arm = 0;
}
} else { # $x == -1
if ($y) {
$arm = 2;
} else {
$arm = 3;
### flip ...
$n = $npow-1-$n;
}
}
### $arm
my $arms_count = $self->arms_count;
if ($arm > $arms_count) {
return undef;
}
return $n * $arms_count + $arm;
}
foreach my $arms (4,3,1,2) {
### $arms
my $path = Math::PlanePath::DragonMidpoint->new (arms => $arms);
for (my $n = 0; $n < 50; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or next;
my $rn = xy_to_n($path,$x,$y);
my $good = '';
if (defined $rn && $rn == $n) {
$good .= "good N";
}
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $rn2 = Math::BaseCnv::cnv($rn,10,2);
printf "n=%d xy=%d,%d got rn=%d %s\n",
$n,$x,$y,
$rn,
$good;
}
}
exit 0;
}
{
# tiling
require Image::Base::Text;
require Math::PlanePath::R5DragonCurve;
my $path = Math::PlanePath::R5DragonCurve->new;
my $width = 37;
my $height = 21;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my $xscale = 3;
my $yscale = 2;
my $w2 = int(($width+1)/2);
my $h2 = int($height/2);
$w2 -= $w2 % $xscale;
$h2 -= $h2 % $yscale;
my $affine = sub {
my ($x,$y) = @_;
return ($x*$xscale + $w2,
-$y*$yscale + $h2);
};
my ($n_lo, $n_hi) = $path->rect_to_n_range(-$w2/$xscale, -$h2/$yscale,
$w2/$xscale, $h2/$yscale);
print "n to $n_hi\n";
foreach my $n ($n_lo .. $n_hi) {
next if ($n % 5) == 2;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
foreach (1 .. 4) {
$image->line ($affine->($x,$y),
$affine->($next_x,$next_y),
($x==$next_x ? '|' : '-'));
$image->xy ($affine->($x,$y),
'+');
$image->xy ($affine->($next_x,$next_y),
'+');
($x,$y) = (-$y,$x); # rotate +90
($next_x,$next_y) = (-$next_y,$next_x); # rotate +90
}
}
$image->xy ($affine->(0,0),
'o');
$image->save('/dev/stdout');
exit 0;
}
{
# min/max for level
# radial extent
#
# dist0to5 = sqrt(1*1+2*2) = sqrt(5)
#
# 4-->5
# ^
# |
# 3<--2
# ^
# |
# 0-->1
#
# Rlevel = sqrt(5)^level + Rprev
# = sqrt(5) + sqrt(5)^2 + ... + sqrt(5)^(level-1) + sqrt(5)^level
# if level
# = sqrt(5) + sqrt(5)^2 + sqrt(5)*sqrt(5)^2 + ...
# = sqrt(5) + (1+sqrt(5))*5^1 + (1+sqrt(5))*5^2 + ...
# = sqrt(5) + (1+sqrt(5))* [ 5^1 + 5^2 + ... ]
# = sqrt(5) + (1+sqrt(5))* (5^k - 1)/4
# <= 5^k
# Rlevel^2 <= 5^level
require Math::BaseCnv;
require Math::PlanePath::R5DragonCurve;
my $path = Math::PlanePath::R5DragonCurve->new;
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 10; $level++) {
my $n_start = 5**($level-1);
my $n_end = 5**$level;
my $min_hypot = 128*$n_end*$n_end;
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + $y*$y;
if ($h < $min_hypot) {
$min_hypot = $h;
$min_pos = "$x,$y";
}
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $prev_min;
my $min_hypot_5 = Math::BaseCnv::cnv($min_hypot,10,5);
print " min r^2 $min_hypot ${min_hypot_5}[5] at $min_pos factor $factor\n";
}
{
my $factor = $max_hypot / $prev_max;
my $max_hypot_5 = Math::BaseCnv::cnv($max_hypot,10,5);
print " max r^2 $max_hypot ${max_hypot_5}[5]) at $max_pos factor $factor\n";
}
$prev_min = $min_hypot;
$prev_max = $max_hypot;
}
exit 0;
}
{
# 2i+1 powers
my $x = 1;
my $y = 0;
foreach (1 .. 10) {
($x,$y) = ($x - 2*$y,
$y + 2*$x);
print "$x $y\n";
}
exit 0;
}
{
# turn sequence
require Math::NumSeq::PlanePathTurn;
my @want = (0);
foreach (1 .. 5) {
@want = map { $_ ? (0,0,1,1,1) : (0,0,1,1,0) } @want;
}
my @got;
foreach my $i (1 .. @want) {
push @got, calc_n_turn($i);
}
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'R5DragonCurve',
# turn_type => 'Right');
# while (@got < @want) {
# my ($i,$value) = $seq->next;
# push @got, $value;
# }
my $got = join(',',@got);
my $want = join(',',@want);
print "$got\n";
print "$want\n";
if ($got ne $want) {
die;
}
exit 0;
# return 0 for left, 1 for right
sub calc_n_turn {
my ($n) = @_;
$n or die;
for (;;) {
if (my $digit = $n % 5) {
return ($digit >= 3 ? 1 : 0);
}
$n = int($n/5);
}
}
}
Math-PlanePath-113/devel/greek-key.pl 0000644 0001750 0001750 00000005611 11774517323 015233 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX 'floor';
use List::Util 'min', 'max';
use Math::PlanePath::GreekKeySpiral;
# uncomment this to run the ### lines
use Smart::Comments;
{
{
package Math::PlanePath::GreekKeySpiral;
sub new {
my $self = shift->SUPER::new (@_);
my $turns = $self->{'turns'};
if (! defined $turns) {
$turns = 2;
} elsif ($turns < 0) {
}
$self->{'turns'} = $turns;
$self->{'centre_x'} = int($turns/2);
$self->{'centre_y'} = int(($turns+1)/2);
$self->{'midpoint'} = ($turns+1)*$turns/2;
return $self;
}
}
sub _n_part_to_xy {
my ($self, $n) = @_;
### _n_part_to_xy(): $n
# if ($rot & 2) {
# $y = -$y;
# }
# if ($d & 1) {
# $x = -$x;
# }
#
# my $d = int((sqrt(-8*$n-7) + 1) / 2);
# $x = $n;
# $y = 0;
# } elsif (($n -= 1) < 0) {
# ### centre ...
# $x = + $n;
# $y = $self->{'centre_y'};
# $rot = $self->{'turns'};
# } else {
# $rot = $d;
# $x = $n;
# $y = 0;
# }
}
my $turns = 6;
my $self = Math::PlanePath::GreekKeySpiral->new (turns => $turns);
### $self
foreach my $n (# 20 .. ($turns+1)**2
0, 6, 11, 15, 18, 20, 21,
21.25,
21.75,
22, 23, 25, 28, 32, 37, 43, 49
) {
my $nn = $n;
my $n = $n;
my $rot = $self->{'turns'};
my $centre_x = $self->{'centre_x'};
my $centre_y = $self->{'centre_y'};
if (($n -= $self->{'midpoint'}) <= 0) {
$n = -$n;
$rot += 0;
$centre_x += 1;
} elsif ($n < 1) {
$rot -= 1;
$centre_x += 1;
} else {
$n -= 1;
$rot += 2;
}
my $d = int((sqrt(8*$n + 1) + 1) / 2);
$n -= $d*($d-1)/2;
my $half = int($d/2);
my $x = $half - $n;
my $y = $n*0 - $half;
if (($d % 4) == 2) {
$x -= 1;
}
if (($d % 4) == 3) {
$y -= 1;
}
$rot -= $d;
if ($rot & 2) {
$x = -$x;
$y = -$y;
}
if ($rot & 1) {
($x,$y) = (-$y,$x);
}
$x += $centre_x;
$y += $centre_y;
$rot &= 3;
print "$nn $d,$n,rot=$rot $x,$y\n";
}
exit 0;
}
Math-PlanePath-113/devel/vogel.pl 0000644 0001750 0001750 00000023161 12067770710 014461 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX 'fmod';
use List::Util 'min', 'max';
use Math::Libm 'M_PI', 'hypot';
use Math::Trig 'pi';
use POSIX;
use Smart::Comments;
use constant PHI => (1 + sqrt(5)) / 2;
{
require Math::PlanePath::VogelFloret;
my $width = 79;
my $height = 21;
my $x_factor = 1.4;
my $y_factor = 2;
my $n_hi = 99;
require Math::NumSeq::OEIS;
my $seq = Math::NumSeq::OEIS->new(anum => 'A000201');
print_class('Math::PlanePath::VogelFloret');
require Math::NumSeq::FibonacciWord;
$seq = Math::NumSeq::FibonacciWord->new;
$y_factor = 1.2;
$n_hi = 73;
print_class('Math::PlanePath::VogelFloret');
sub print_class {
my ($name) = @_;
# secret leading "*Foo" means print if available
my $if_available = ($name =~ s/^\*//);
my $class = $name;
unless ($class =~ /::/) {
$class = "Math::PlanePath::$class";
}
($class, my @parameters) = split /\s*,\s*/, $class;
$class =~ /^[a-z_][:a-z_0-9]*$/i or die "Bad class name: $class";
if (! eval "require $class") {
if ($if_available) {
next;
} else {
die $@;
}
}
@parameters = map { /(.*?)=(.*)/ or die "Missing value for parameter \"$_\"";
$1,$2 } @parameters;
my %rows;
my $x_min = 0;
my $x_max = 0;
my $y_min = 0;
my $y_max = 0;
my $cellwidth = 1;
my $path = $class->new (width => POSIX::ceil($width / 4),
height => POSIX::ceil($height / 2),
@parameters);
my $x_limit_lo;
my $x_limit_hi;
if ($path->x_negative) {
my $w_cells = int ($width / $cellwidth);
my $half = int(($w_cells - 1) / 2);
$x_limit_lo = -$half;
$x_limit_hi = +$half;
} else {
my $w_cells = int ($width / $cellwidth);
$x_limit_lo = 0;
$x_limit_hi = $w_cells - 1;
}
my $y_limit_lo = 0;
my $y_limit_hi = $height-1;
if ($path->y_negative) {
my $half = int(($height-1)/2);
$y_limit_lo = -$half;
$y_limit_hi = +$half;
}
my $is_01 = $seq->characteristic('smaller');
### seq: ref $seq
### $is_01
$rows{0}{0} = '.';
my $n_start = $path->n_start;
my $n = $n_start;
for (;;) {
my ($x, $y) = $path->n_to_xy ($n);
# stretch these out for better resolution
if ($class =~ /Sacks/) { $x *= 1.5; $y *= 2; }
if ($class =~ /Archimedean/) { $x *= 2; $y *= 3; }
if ($class =~ /Theodorus|MultipleRings/) { $x *= 2; $y *= 2; }
if ($class =~ /Vogel/) { $x *= $x_factor; $y *= $y_factor; }
# nearest integers
$x = POSIX::floor ($x + 0.5);
$y = POSIX::floor ($y + 0.5);
my $cell = $rows{$x}{$y};
if (defined $cell) { $cell .= ','; }
if ($is_01) {
$cell .= $seq->ith($n);
} else {
$cell .= $n;
}
my $new_cellwidth = max ($cellwidth, length($cell) + 1);
my $new_x_limit_lo;
my $new_x_limit_hi;
if ($path->x_negative) {
my $w_cells = int ($width / $new_cellwidth);
my $half = int(($w_cells - 1) / 2);
$new_x_limit_lo = -$half;
$new_x_limit_hi = +$half;
} else {
my $w_cells = int ($width / $new_cellwidth);
$new_x_limit_lo = 0;
$new_x_limit_hi = $w_cells - 1;
}
my $new_x_min = min($x_min, $x);
my $new_x_max = max($x_max, $x);
my $new_y_min = min($y_min, $y);
my $new_y_max = max($y_max, $y);
if ($new_x_min < $new_x_limit_lo
|| $new_x_max > $new_x_limit_hi
|| $new_y_min < $y_limit_lo
|| $new_y_max > $y_limit_hi) {
last;
}
$rows{$x}{$y} = $cell;
$cellwidth = $new_cellwidth;
$x_limit_lo = $new_x_limit_lo;
$x_limit_hi = $new_x_limit_hi;
$x_min = $new_x_min;
$x_max = $new_x_max;
$y_min = $new_y_min;
$y_max = $new_y_max;
if ($is_01) {
$n++;
} else {
(my $i, $n) = $seq->next;
}
last if $n > $n_hi;
}
$n--; # the last N actually plotted
print "$name N=$n_start to N=$n\n\n";
foreach my $y (reverse $y_min .. $y_max) {
foreach my $x ($x_limit_lo .. $x_limit_hi) {
my $cell = $rows{$x}{$y};
if (! defined $cell) { $cell = ''; }
printf ('%*s', $cellwidth, $cell);
}
print "\n";
}
}
exit 0;
}
sub cont {
my $ret = pop;
while (@_) {
$ret = (pop @_) + 1/$ret;
}
return $ret;
}
### phi: cont(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
{
# use constant ROTATION => M_PI-3;
# use constant ROTATION => PHI;
#use constant ROTATION => sqrt(37);
use constant ROTATION => cont(1 .. 20);
my $margin = 0.999;
# use constant K => 6;
# use constant ROTATION => (K + sqrt(4+K*K)) / 2;
print "ROTATION ",ROTATION,"\n";
my @n;
my @r;
my @x;
my @y;
my $prev_d = 5;
my $min_d = 5;
my $min_n1 = 0;
my $min_n2 = 0;
my $min_x2 = 0;
my $min_y2 = 0;
for (my $n = 1; $n < 100_000_000; $n++) {
my $r = sqrt($n);
my $theta = $n * ROTATION() * 2*pi(); # radians
my $x = $r * cos($theta);
my $y = $r * sin($theta);
foreach my $i (0 .. $#n) {
my $d = hypot ($x-$x[$i], $y-$y[$i]);
if ($d < $min_d) {
$min_d = $d;
$min_n1 = $n[$i];
$min_n2 = $n;
$min_x2 = $x;
$min_y2 = $y;
if ($min_d / $prev_d < $margin) {
$prev_d = $min_d;
print "$min_n1 $min_n2 $min_d ", 1/$min_d, "\n";
print " x=$min_x2 y=$min_y2\n";
}
}
}
push @n, $n;
push @r, $r;
push @x, $x;
push @y, $y;
if ((my $r_lo = sqrt($n) - 1.2 * $min_d) > 0) {
while (@n > 1) {
if ($r[0] >= $r_lo) {
last;
}
shift @r;
shift @n;
shift @x;
shift @y;
}
}
}
print "$min_n1 $min_n2 $min_d ", 1/$min_d, "\n";
print " x=$min_x2 y=$min_y2\n";
exit 0;
}
{
my $x = 3;
foreach (1 .. 100) {
$x = 1 / (1 + $x);
}
}
# {
# # 609 631 0.624053229799566 1.60242740883046
# # 2 7 1.47062247517163 0.679984167849259
#
# use constant ROTATION => M_PI-3;
# my @x;
# my @y;
# foreach my $n (1 .. 20000) {
# my $r = sqrt($n);
# # my $theta = 2 * $n; # radians
# my $theta = $n * ROTATION() * 2*pi(); # radians
# push @x, $r * cos($theta);
# push @y, $r * sin($theta);
# }
# # ### @x
# my $min_d = 999;
# my $min_i = 0;
# my $min_j = 0;
# my $min_xi = 0;
# my $min_yi = 0;
# foreach my $i (0 .. $#x-1) {
# my $xi = $x[$i];
# my $yi = $y[$i];
# foreach my $j ($i+1 .. $#x) {
# my $d = hypot ($xi-$x[$j], $yi-$y[$j]);
# if ($d < $min_d) {
# $min_d = $d;
# $min_i = $i;
# $min_j = $j;
# $min_xi = $xi;
# $min_yi = $yi;
# }
# }
# }
# print "$min_i $min_j $min_d ", 1/$min_d, "\n";
# print " x=$min_xi y=$min_yi\n";
# exit 0;
# }
# {
# require Math::PlanePath::VogelFloret;
# use constant FACTOR => do {
# my @c = map {
# my $n = $_;
# my $r = sqrt($n);
# my $revs = $n / (PHI * PHI);
# my $theta = $revs * 2*M_PI();
# ### $n
# ### $r
# ### $revs
# ### $theta
# ($r*cos($theta), $r*sin($theta))
# } 1, 4;
# ### @c
# ### hypot: hypot ($c[0]-$c[2], $c[1]-$c[3])
# 1 / hypot ($c[0]-$c[2], $c[1]-$c[3])
# };
# ### FACTOR: FACTOR()
#
# print "FACTOR ", FACTOR(), "\n";
# # print "FACTOR ", Math::PlanePath::VogelFloret::FACTOR(), "\n";
# exit 0;
# }
{
foreach my $i (0 .. 20) {
my $f = PHI**$i/sqrt(5);
my $rem = fmod($f,PHI);
printf "%11.5f %6.5f\n", $f, $rem;
}
exit 0;
}
{
foreach my $n (18239,19459,25271,28465,31282,35552,43249,74592,88622,
101898,107155,116682) {
my $theta = $n / (PHI * PHI); # 1==full circle
printf "%6d %.2f\n", $n, $theta;
}
exit 0;
}
foreach my $i (2 .. 5000) {
my $rem = fmod ($i, PHI*PHI);
if ($rem > 0.5) {
$rem = $rem - 1;
}
if (abs($rem) < 0.02) {
printf "%4d %6.3f %s\n", $i,$rem,factorize($i);
}
}
sub factorize {
my ($n) = @_;
my @factors;
foreach my $f (2 .. int(sqrt($n)+1)) {
if (($n % $f) == 0) {
push @factors, $f;
$n /= $f;
while (($n % $f) == 0) {
$n /= $f;
}
}
}
return join ('*',@factors);
}
exit 0;
# pi => { rotation_factor => M_PI() - 3,
# rfactor => 2,
# # ever closer ?
# # 298252 298365 0.146295611059244 6.83547505464836
# # x=-142.771526420416 y=527.239311170539
# },
# # BEGIN {
# # foreach my $info (rotation_types()) {
# # my $rot = $info->{'rotation_factor'};
# # my $n1 = $info->{'closest_Ns'}->[0];
# # my $r1 = sqrt($n1);
# # my $t1 = $n1 * $rot * 2*M_PI();
# # my $x1 = cos ($t1);
# # my $y1 = sin ($t1);
# #
# # my $r2 = sqrt($n2);
# # my $t2 = $n2 * $rot * 2*M_PI();
# # my $x2 = cos ($t2);
# # my $y2 = sin ($t2);
# #
# # $info->{'rfactor'} = 1 / hypot ($x1-$x2, $y1-$y2);
# # }
# # }
Math-PlanePath-113/devel/beta-omega.pl 0000644 0001750 0001750 00000003264 12000731464 015336 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::Base::Digits 'round_down_pow';
# uncomment this to run the ### lines
use Smart::Comments;
use Math::PlanePath::BetaOmega;
use Math::PlanePath::KochCurve;
{
require Math::BaseCnv;
my $path = Math::PlanePath::BetaOmega->new;
foreach my $n (0 .. 64) {
my $n4 = sprintf '%3s', Math::BaseCnv::cnv($n,10,4);
my ($x,$y) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
my $dx = $x2-$x;
my $dy = $y2-$y;
print "$n4 $dx,$dy\n";
}
exit 0;
}
{
require Math::PlanePath::KochCurve;
foreach my $y (reverse -16 .. 22) {
my $y1 = $y;
my $y2 = $y;
{
if ($y2 > 0) {
# eg y=5 gives 3*5 = 15
$y2 *= 3;
} else {
# eg y=-2 gives 1-3*-2 = 7
$y2 = 1-3*$y1;
}
my ($ylen, $ylevel) = round_down_pow($y2,2);
($ylen, $ylevel) = Math::PlanePath::BetaOmega::_y_round_down_len_level($y);
print "$y $y2 $ylevel $ylen\n";
}
}
exit 0;
}
Math-PlanePath-113/devel/dragon-pgf.tex 0000644 0001750 0001750 00000013505 12241237046 015551 0 ustar gg gg %% Copyright 2013 Kevin Ryde
%%
%% This file is part of Math-PlanePath.
%%
%% Math-PlanePath 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, or (at your option) any later
%% version.
%%
%% Math-PlanePath 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 Math-PlanePath. If not, see .
%% ----------------------------------------------------------------------------
%% plain tex
\input tikz.tex
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{S}{\pgflsystemdrawforward}
\rule{F -> F+S}
\rule{S -> F-S}
}
\tikzpicture
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=8}]
lindenmayer system;
\endtikzpicture
\bye
%% ----------------------------------------------------------------------------
%% angle 45 so direction across is fixed, using foreach
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\begin{document}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{S}{\pgflsystemdrawforward}
\rule{F -> -F++S-}
\rule{S -> +F--S+}
}
\foreach \x in {1,...,7} {
\hbox{
order=\x
\hspace{.5em}
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=\x}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
}
\vspace{.5ex}
}
\end{document}
\bye
%% ----------------------------------------------------------------------------
%% angle 45 so direction across is fixed
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\begin{document}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{R}{\pgflsystemdrawforward}
\rule{F -> -F++R-}
\rule{R -> +F--R+}
}
one
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=1}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
two
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=2}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
three
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=3}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
four
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=4}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
five
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=5}]
lindenmayer system;
\end{tikzpicture}
\vspace{5ex}
eight
\hspace{1em}
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt,angle=45, axiom=F, order=8}]
lindenmayer system;
\end{tikzpicture}
\end{document}
\bye
%% ----------------------------------------------------------------------------
%% latex
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\begin{document}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{R}{\pgflsystemdrawforward}
\rule{F -> F+R+}
\rule{R -> -F-R}
}
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=8}]
lindenmayer system;
\end{tikzpicture}
\end{document}
\bye
%% ----------------------------------------------------------------------------
%% levels of expansion
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\begin{document}
\pgfdeclarelindenmayersystem{Dragon curve}{
\symbol{R}{\pgflsystemdrawforward}
\rule{F -> F+R+}
\rule{R -> -F-R}
}
one
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=1}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
two
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=2}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
three
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=3}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
four
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=4}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
five
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=5}]
lindenmayer system;
\end{tikzpicture}
\hspace{1em}
\vspace{5ex}
eight
\hspace{1em}
\begin{tikzpicture}[baseline=0pt]
\draw
[lindenmayer system={Dragon curve, step=10pt, axiom=F, order=8}]
lindenmayer system;
\end{tikzpicture}
\end{document}
\bye
%% ----------------------------------------------------------------------------
%% \begin{document}
%% \begin{tikzpicture}
%% \pgfdeclarelindenmayersystem{Dragon curve}{
%% \symbol{R}{\pgflsystemdrawforward}
%% \rule{F -> +F--R+}
%% \rule{R -> -R++F-}
%% }
%% \draw
%% [lindenmayer system={Dragon curve, step=10pt, angle=45,angle=45, axiom=F, order=3}]
%% lindenmayer system;
%% \end{tikzpicture}
%% \end{document}
%% \bye
%% \begin{tikzpicture}
%% \draw [green!50!black, rotate=90]
%% [l-system={rule set={L -> L+R+, R -> R-L-}, axiom=L, order=5, step=5pt, angle=90}]
%% lindenmayer system;
%% \end{tikzpicture}
%%
%% picture
%% \begin{tikzpicture}
%% \pgfdeclarelindenmayersystem{Dragon curve}{
%% \rule{L -> L+RF+}
%% \rule{R -> -FL-R}}
%% }
%% \draw
%% [rotate=0]
%% [l-system={Dragon curve, step=10pt, angle=90, axiom=FL, order=7}]
%% lindenmayer system;
%% \end{tikzpicture}
%%
%% picture
%% \end{document}
Math-PlanePath-113/devel/flowsnake.pl 0000644 0001750 0001750 00000041544 12112305551 015327 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::Libm 'M_PI', 'hypot';
use Math::PlanePath;;
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments;
{
require Math::NumSeq::PlanePathDelta;
require Math::PlanePath::Flowsnake;
my $class = 'Math::PlanePath::Flowsnake';
my $path = $class->new;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath_object=>$path,
delta_type => 'TDir6');
sub path_n_to_tturn6 {
my ($n) = @_;
if ($n < 1) { return undef; }
my $turn6 = $seq->ith($n) - $seq->ith($n-1);
if ($turn6 > 3) { $turn6 -= 6; }
return $turn6;
}
# N to Turn by recurrence
sub calc_n_to_tturn6 { # not working
my ($n) = @_;
if ($n < 1) { return undef; }
if ($n % 49 == 0) {
return calc_n_to_tturn6($n/7);
}
if (int($n/7) % 7 == 3) { # "_3_"
return calc_n_to_tturn6(($n%7) + int($n/49));
}
return path_n_to_tturn6($n);
if ($n == 1) { return 1; }
if ($n == 2) { return 2; }
if ($n == 3) { return -1; }
if ($n == 4) { return -2; }
if ($n == 5) { return 0; }
if ($n == 6) { return -1; }
my @digits = digit_split_lowtohigh($n,7);
my $high = pop @digits;
if ($digits[-1]) {
}
$n = digit_join_lowtohigh(\@digits,7,0);
if ($n == 0) {
return 0;
}
return calc_n_to_tturn6($n);
}
{
for (my $n = 1; $n < 7**3; $n+=1) {
my $value = path_n_to_tturn6($n);
my $calc = calc_n_to_tturn6($n);
my $diff = ($value != $calc ? ' ***' : '');
print "$n $value $calc$diff\n";
}
exit 0;
}
exit 0;
}
{
# N to Dir6 -- working for integers
require Math::PlanePath::Flowsnake;
require Math::NumSeq::PlanePathDelta;
my @next_state = (0,7,7,0,0,0,7,
0,7,7,7,0,0,7);
my @tdir6 = (0,1,3,2,0,0,-1,
-1,0,0,2,3,1,0);
sub n_to_totalturn6 {
my ($self, $n) = @_;
unless ($n >= 0) {
return undef;
}
my $state = 0;
my $tdir6 = 0;
foreach my $digit (reverse digit_split_lowtohigh($n,7)) {
$state += $digit;
$tdir6 += $tdir6[$state];
$state = $next_state[$state];
}
return $tdir6 % 6;
}
{
my $class = 'Math::PlanePath::Flowsnake';
my $path = $class->new;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath=>'Flowsnake',
delta_type => 'TDir6');
for (my $n = 0; $n < 7**3; $n+=1) {
my $value = $seq->ith($n);
my $tdir6 = n_to_totalturn6($path,$n) % 6;
my $diff = ($value != $tdir6 ? ' ***' : '');
print "$n $value $tdir6$diff\n";
}
exit 0;
}
# sub _digit_lowest {
# my ($n, $radix) = @_;
# my $digit;
# for (;;) {
# last if ($digit = ($n % 7));
# $n /= 7;
# last unless $n;
# }
# # if ($digit < 1_000_000) {
# # $digit = "$digit";
# # }
# return $digit;
# }
}
{
# N to Turn6 -- working for integers
require Math::PlanePath::Flowsnake;
require Math::NumSeq::PlanePathDelta;
my $class = 'Math::PlanePath::Flowsnake';
my $path = $class->new;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath=>'Flowsnake',
delta_type => 'TDir6');
for (my $n = 1; $n < 7**4; $n+=1) {
my $value = ($seq->ith($n) - $seq->ith($n-1)) % 6;
$value += 2; # range -2 to +2
$value %= 6;
$value -= 2;
my $turn = $path->_WORKING_BUT_SECRET__n_to_turn6($n);
my $diff = ($value != $turn ? ' ***' : '');
print "$n $value $turn$diff\n";
die if $value != $turn;
}
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
my $f = Math::PlanePath::Flowsnake->new (arms => 2);
my $c = Math::PlanePath::FlowsnakeCentres->new (arms => 2);
my $width = 5;
my %saw;
foreach my $n (0 .. 7**($width-1)) {
my ($x,$y) = $f->n_to_xy($n);
my $cn = $c->xy_to_n($x,$y) // -1;
my $cr = $c->xy_to_n($x+2, $y) // -1;
my $ch = $c->xy_to_n($x+1,$y+1) // -1;
my $cw = $c->xy_to_n($x-1,$y+1) // -1;
my $cl = $c->xy_to_n($x-2,$y) // -1; # <------
my $cu = $c->xy_to_n($x-1,$y-1) // -1; # <------3
my $cz = $c->xy_to_n($x+1,$y-1) // -1;
if ($n == $cn) { $saw{'n'} = 0; }
if ($n == $cr) { $saw{'r'} = 1; }
if ($n == $ch) { $saw{'h'} = 2; }
if ($n == $cw) { $saw{'w'} = 3; }
if ($n == $cl) { $saw{'l'} = 4; }
if ($n == $cu) { $saw{'u'} = 5; }
if ($n == $cz) { $saw{'z'} = 6; }
unless (($n == $cn)
|| ($n == $cr)
|| ($n == $ch)
|| ($n == $cw)
|| ($n == $cl)
|| ($n == $cu)
|| ($n == $cz)) {
die "no match $n: $cn,$cr,$ch,$cw,$cl,$cu,$cz";
}
}
my $saw = join(',', sort {$saw{$a}<=>$saw{$b}} keys %saw);
print "$saw\n";
exit 0;
}
{
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
say Math::PlanePath::Flowsnake->isa('Math::PlanePath::FlowsnakeCentres');
say Math::PlanePath::FlowsnakeCentres->isa('Math::PlanePath::Flowsnake');
say Math::PlanePath::Flowsnake->can('xy_to_n');
say Math::PlanePath::FlowsnakeCentres->can('xy_to_n');
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
my $c = Math::PlanePath::Flowsnake->new;
my $f = Math::PlanePath::FlowsnakeCentres->new;
my $width = 5;
my %saw;
foreach my $n (0 .. 7**($width-1)) {
my $n7 = sprintf '%*s', $width, Math::BaseCnv::cnv($n,10,7);
my ($x,$y) = $f->n_to_xy($n);
my $cn = $c->xy_to_n($x,$y) || -1;
my $cn7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cn,10,7);
my $rx = $x + 1;
my $ry = $y + 1;
my $cr = $c->xy_to_n($rx,$ry) || -1;
my $cr7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cr,10,7);
my $hx = $x + 1;
my $hy = $y + 1;
my $ch = $c->xy_to_n($hx,$hy) || -1;
my $ch7 = sprintf '%*s', $width, Math::BaseCnv::cnv($ch,10,7);
my $wx = $x - 1;
my $wy = $y + 1;
my $cw = $c->xy_to_n($wx,$wy) || -1;
my $cw7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cw,10,7);
my $lx = $x - 2;
my $ly = $y;
my $cl = $c->xy_to_n($lx,$ly) || -1;
my $cl7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cl,10,7);
my $ux = $x - 1;
my $uy = $y - 1;
my $cu = $c->xy_to_n($ux,$uy) || -1;
my $cu7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cu,10,7);
my $zx = $x + 1;
my $zy = $y - 1;
my $cz = $c->xy_to_n($zx,$zy) || -1;
my $cz7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cz,10,7);
if ($n == $cn) { $saw{'n'} = 0; }
if ($n == $cr) { $saw{'r'} = 1; }
if ($n == $ch) { $saw{'h'} = 2; }
if ($n == $cw) { $saw{'w'} = 3; }
if ($n == $cl) { $saw{'l'} = 4; }
if ($n == $cu) { $saw{'u'} = 5; }
if ($n == $cz) { $saw{'z'} = 6; }
my $bad = ($n == $cn
|| $n == $cr
|| $n == $ch
|| $n == $cw
|| $n == $cl
|| $n == $cu
|| $n == $cz
? ''
: ' ******');
# print "$n7 $cn7 $ch7 $cw7 $cu7 $bad\n";
}
my $saw = join(',', sort {$saw{$a}<=>$saw{$b}} keys %saw);
print "$saw\n";
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
foreach my $y (reverse -5 .. 40) {
printf "%3d ", $y;
foreach my $x (-20 .. 15) {
my $n = $path->xy_to_n($x,$y);
if (! defined $n) {
print " ";
next;
}
my $nh = $n - ($n%7);
my ($hx,$hy) = $path->n_to_xy($nh);
my $pos = '?';
if ($hy > $y) {
$pos = 'T';
} elsif ($hx > $x) {
$pos = '.';
} else {
$pos = '*';
$pos = $n%7;
}
print "$pos ";
}
print "\n";
}
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
my $f = Math::PlanePath::Flowsnake->new;
my $c = Math::PlanePath::FlowsnakeCentres->new;
my $width = 5;
foreach my $n (0 .. 7**($width-1)) {
my $n7 = sprintf '%*s', $width, Math::BaseCnv::cnv($n,10,7);
my ($x,$y) = $f->n_to_xy($n);
my $cn = $c->xy_to_n($x,$y) || 0;
my $cn7 = sprintf '%*s', $width, Math::BaseCnv::cnv($cn,10,7);
my $m = ($x + 2*$y) % 7;
if ($m == 2) { # 2,0 = 2
$x -= 2;
} elsif ($m == 5) { # 3,1 = 3+2*1 = 5
$x -= 3;
$y -= 1;
} elsif ($m == 3) { # 1,1 = 1+2 = 3
$x -= 1;
$y -= 1;
} elsif ($m == 4) { # 0,2 = 0+2*2 = 4
$y -= 2;
} elsif ($m == 6) { # 2,2 = 2+2*2 = 6
$x -= 2;
$y -= 2;
} elsif ($m == 1) { # 4,2 = 4+2*2 = 8 = 1
$x -= 4;
$y -= 2;
}
my $mn = $c->xy_to_n($x,$y) || 0;
my $mn7 = sprintf '%*s', $width, Math::BaseCnv::cnv($mn,10,7);
my $nh = $n - ($n%7);
my $mh = $mn - ($mn%7);
my $diff = ($nh == $mh ? "" : " **");
print "$n7 $mn7 $cn7$diff\n";
}
exit 0;
}
{
# xy_to_n
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
my $path = Math::PlanePath::FlowsnakeCentres->new;
my $k = 4000;
my ($n_lo,$n_hi) = $path->rect_to_n_range(-$k,-$k, $k,$k);
print "$n_lo, $n_hi\n";
exit 0;
}
{
# xy_to_n
require Math::PlanePath::Flowsnake;
require Math::PlanePath::FlowsnakeCentres;
my $path = Math::PlanePath::FlowsnakeCentres->new;
my $y = 0;
for (my $x = 6; $x >= -5; $x-=2) {
$x -= ($x^$y)&1;
my $n = $path->xy_to_n($x,$y);
print "$x,$y ",($n//'undef'),"\n";
}
exit 0;
}
{
# modulo
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
for (my $n = 0; $n <= 49; $n++) {
if (($n % 7) == 0) { print "\n"; }
my ($x,$y) = $path->n_to_xy($n);
my $c = $x + 2*$y;
my $m = $c % 7;
print "$n $x,$y $c $m\n";
}
exit 0;
}
{
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
for (my $n = 0; $n <= 49; $n+=7) {
my ($x,$y) = $path->n_to_xy($n);
my ($rx,$ry) = ((3*$y + 5*$x) / 14,
(5*$y - $x) / 14);
print "$n $x,$y $rx,$ry\n";
}
exit 0;
}
{
# radius
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
my $prev_max = 1;
for (my $level = 1; $level < 10; $level++) {
print "level $level\n";
my ($x2,$y2) = $path->n_to_xy(2 * 7**($level-1));
my ($x3,$y3) = $path->n_to_xy(3 * 7**($level-1));
my $cx = ($x2+$x3)/2;
my $cy = ($y2+$y3)/2;
my $max_hypot = 0;
my $max_pos = '';
foreach my $n (0 .. 7**$level - 1) {
my ($x,$y) = $path->n_to_xy($n);
my $h = ($x-$cx)**2 + 3*($y-$cy);
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
my $factor = $max_hypot / $prev_max;
$prev_max = $max_hypot;
print " cx=$cx,cy=$cy max $max_hypot at $max_pos factor $factor\n";
}
exit 0;
}
{
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
my $prev_max = 1;
for (my $level = 1; $level < 10; $level++) {
my $n_start = 0;
my $n_end = 7**$level - 1;
my $min_hypot = $n_end;
my $min_x = 0;
my $min_y = 0;
my $max_hypot = 0;
my $max_pos = '';
print "level $level\n";
my ($xend,$yend) = $path->n_to_xy(7**($level-1));
print " end $xend,$yend\n";
$yend *= sqrt(3);
my $cx = -$yend; # rotate +90
my $cy = $xend;
print " rot90 $cx, $cy\n";
# $cx *= sqrt(3/4) * .5;
# $cy *= sqrt(3/4) * .5;
$cx *= 1.5;
$cy *= 1.5;
print " scale $cx, $cy\n";
$cx += $xend;
$cy += $yend;
print " offset to $cx, $cy\n";
$cy /= sqrt(3);
printf " centre %.1f, %.1f\n", $cx,$cy;
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = ($cx-$x)**2 + 3*($cy-$y)**2;
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
# if ($h < $min_hypot) {
# $min_hypot = $h;
# $min_x = $x;
# $min_y = $y;
# }
}
# print " min $min_hypot at $min_x,$min_y\n";
my $factor = $max_hypot / $prev_max;
print " max $max_hypot at $max_pos factor $factor\n";
$prev_max = $max_hypot;
}
exit 0;
}
{
# diameter
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
my $prev_max = 1;
for (my $level = 1; $level < 10; $level++) {
print "level $level\n";
my $n_start = 0;
my $n_end = 7**$level - 1;
my ($xend,$yend) = $path->n_to_xy($n_end);
print " end $xend,$yend\n";
my @x;
my @y;
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
push @x, $x;
push @y, $y;
}
my $max_hypot = 0;
my $max_pos = '';
my ($cx,$cy);
foreach my $i (0 .. $#x-1) {
foreach my $j (1 .. $#x) {
my $h = ($x[$i]-$x[$j])**2 + 3*($y[$i]-$y[$j]);
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x[$i],$y[$i], $x[$j],$y[$j]";
$cx = ($x[$i] + $x[$j]) / 2;
$cy = ($y[$i] + $y[$j]) / 2;
}
}
}
my $factor = $max_hypot / $prev_max;
print " max $max_hypot at $max_pos factor $factor\n";
$prev_max = $max_hypot;
}
exit 0;
}
{
require Math::PlanePath::GosperIslands;
my $path = Math::PlanePath::GosperIslands->new;
foreach my $level (0 .. 20) {
my $n_start = 3**($level+1) - 2;
my $n_end = 3**($level+2) - 2 - 1;
my ($prev_x) = $path->n_to_xy($n_start);
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
# if ($y == 0 && $x > 0) {
# print "level $level x=$x y=$y n=$n\n";
# }
if (($prev_x>0) != ($x>0) && $y > 0) {
print "level $level x=$x y=$y n=$n\n";
}
$prev_x = $x;
}
print "\n";
}
exit 0;
}
sub hij_to_xy {
my ($h, $i, $j) = @_;
return ($h*2 + $i - $j,
$i+$j);
}
{
# y<0 at n=8598 x=-79,y=-1
require Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
for (my $n = 3; ; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if ($y == 0) {
print "zero n=$n $x,$y\n";
}
if ($y < 0) {
print "yneg n=$n $x,$y\n";
exit 0;
}
# if ($y < 0 && $x >= 0) {
# print "yneg n=$n $x,$y\n";
# exit 0;
# }
}
exit 0;
}
{
{
my $sh = 1;
my $si = 0;
my $sj = 0;
my $n = 1;
foreach my $level (1 .. 20) {
$n *= 7;
($sh, $si, $sj) = (2*$sh - $sj,
2*$si + $sh,
2*$sj + $si);
my ($x, $y) = hij_to_xy($sh,$si,$sj);
$n = sprintf ("%f",$n);
print "$level $n $sh,$si,$sj $x,$y\n";
}
}
exit 0;
}
our $level;
my $n = 0;
my $x = 0;
my $y = 0;
my %seen;
my @row;
my $x_offset = 8;
my $dir = 0;
sub step {
$dir %= 6;
print "$n $x, $y dir=$dir\n";
my $key = "$x,$y";
if (defined $seen{$key}) {
print "repeat $x, $y from $seen{$key}\n";
}
$seen{"$x,$y"} = $n;
if ($y >= 0) {
$row[$y]->[$x+$x_offset] = $n;
}
if ($dir == 0) { $x += 2; }
elsif ($dir == 1) { $x++, $y++; }
elsif ($dir == 2) { $x--, $y++; }
elsif ($dir == 3) { $x -= 2; }
elsif ($dir == 4) { $x--, $y--; }
elsif ($dir == 5) { $x++, $y--; }
else { die; }
$n++;
}
sub forward {
if ($level == 1) {
step ();
return;
}
local $level = $level-1;
forward(); $dir++; # 0
backward(); $dir += 2; # 1
backward(); $dir--; # 2
forward(); $dir -= 2; # 3
forward(); # 4
forward(); $dir--; # 5
backward(); $dir++; # 6
}
sub backward {
my ($dir) = @_;
if ($level == 1) {
step ();
return;
}
print "backward\n";
local $level = $level-1;
$dir += 2;
forward();
forward();
$dir--; # 5
forward();
$dir--; # 5
forward();
$dir--; # 5
backward();
$dir--; # 5
backward();
$dir--; # 5
forward();
$dir--; # 5
}
$level = 3;
forward (2);
foreach my $y (reverse 0 .. $#row) {
my $aref = $row[$y];
foreach my $x (0 .. $#$aref) {
printf ('%*s', 3, (defined $aref->[$x] ? $aref->[$x] : ''));
}
print "\n";
}
Math-PlanePath-113/devel/dragon.gnuplot 0000644 0001750 0001750 00000015727 12041161313 015666 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
#------------------------------------------------------------------------------
# set terminal png
# set terminal xterm
# set parametric
# something evil happens with "xtics axis", need dummy xlabel
# set xlabel " " 0, -2
# set xrange [-0.5:39.5]
# set xtics axis 5
# set mxtics 5
# set ylabel "Weight (percent)"
#
#set yrange [-5:55]
# set for [i = 1:10] style line i lc rgb "blue"
# plot "foo.data" with lines
# plot for [n=2:10] a=n n,2*n with lines
# plot x,x*x with linespoints pointinterval 5
# plot [1:10] x,2*x with lines
#plot sin(t),t**2 with lines
# bit_above_lowest_0(n) = n & (1 + (n ^ (n-1)))
# num_bits(n) = (n==0 ? 0 : 1+num_bits(int(n/2)))
# dragon_pos(n) = dragon_pos_by_bits(int(n), num_bits(int(n)))
# 1,1 shift +90*b^bit
# 1,0 \rot+90
# 0,1 / shift b^bit
# 0,0
# dragon_pos_by_bits(n,bit) = (bit<0 ? 0 \
# : ((n&(2**(bit+1))) \
# ? (n&(2**bit) \
# ? dragon_pos_by_bits(n,bit-1) + {0,1}*{1,1}**bit \
# : dragon_pos_by_bits(n,bit-1) * {0,1} \
# ) \
# : (n&(2**bit) \
# ? dragon_pos_by_bits(n,bit-1) * {0,1} + {1,1}**bit \
# : dragon_pos_by_bits(n,bit-1) \
# ) \
# ))
# dragon_pos_by_bits(n,bit) = (bit<0 ? 0 \
# : ((n&(2**(bit+1))) \
# ? (n&(2**bit) \
# ? dragon_pos_by_bits(n,bit-1) + ((n&(2**bit)) ? ({1,1}**bit) * ((n&(2**(bit+1))) ? {0,1} : 1) \
# : 0) \
# : dragon_pos_by_bits(n,bit-1) * ((n&(2**(bit+1))) != (n&(2**bit)) ? {0,1} : 1) + ((n&(2**bit)) ? ({1,1}**bit) * ((n&(2**(bit+1))) ? {0,1} : 1) \
# : 0) \
# ) \
# : (n&(2**bit) \
# ? dragon_pos_by_bits(n,bit-1) * ((n&(2**(bit+1))) != (n&(2**bit)) ? {0,1} : 1) + ((n&(2**bit)) ? ({1,1}**bit) * ((n&(2**(bit+1))) ? {0,1} : 1) \
# : 0) \
# : dragon_pos_by_bits(n,bit-1) * ((n&(2**(bit+1))) != (n&(2**bit)) ? {0,1} : 1) + ((n&(2**bit)) ? ({1,1}**bit) * ((n&(2**(bit+1))) ? {0,1} : 1) \
# : 0) \
# ) \
# ))
# dragon_pos_by_bits(n,pos) = (pos<0 ? 0 \
# : dragon_pos_by_bits(n,pos-1) \
# * ((n&(2**(pos+1)))/2 != (n&(2**pos)) ? {0,1} : 1) \
# + ((n&(2**pos)) ? ({1,1}**pos) * ((n&(2**(pos+1))) ? {0,1} : 1) \
# : 0))
# # return 0 or 1 for the bit at position "pos" in n
# # pos==0 is the least significant bit
# bit_at_pos(n,pos) = int(n/(2**pos)) & 1
#
# bit_pair_at_pos(n,pos) = int(n/(2**pos)) & 3
# addfactor(pair) = (pair & 1 \
# ? ((pair & 2) ? {0,1} : 1) \
# : 0)
# multiplier(pair) = (((pair+1)&3) >= 2) ? {0,1} : 1
# dragon_pos_by_bits(n,pos) = (pos<0 ? 0 \
# : ((pair = bit_pair_at_pos(n,pos)), \
# (dragon_pos_by_bits(n,pos-1) \
# * multiplier(pair) \
# + addfactor(pair) * ({1,1}**pos))))
# addfactor(pair) = (pair == 1 ? 1 \
# : pair == 3 ? {0,1} \
# : 0) # pair==0 or pair==2
# multiplier(pair) = (pair == 0 || pair == 3 ? 1 : {0,1})
#
# dragon_pos_by_bits(n,pos) = (pos<0 ? 0 \
# : dragon_pos_by_bits(n,pos-1) \
# * multiplier(bit_pair_at_pos(n,pos)) \
# + addfactor(bit_pair_at_pos(n,pos)) * ({1,1}**pos))
# addfactor(n,pos) = (bit_at_pos(n,pos)
# ? (bit_at_pos(n,pos+1) ? {0,1} : 1)
# : 0)
# multiplier(pair) = (bit_at_pos(n,pos) == bit_at_pos(n,pos+1) ? 1 : {0,1})
#
# dragon_pos_by_bits(n,pos) = (pos<0 ? 0 \
# : addfactor(n,pos) * ({1,1}**pos)
# + multiplier(n,pos) * dragon_pos_by_bits(n,pos-1))
# b={1,1}
# #plot real(b**t),imag(b**t) with points
# # plot int(t),(num_bits(int(t))) with linespoints
# set yrange [-1:length]
# set xrange [-10:10]
# set yrange [-10:10]
#------------------------------------------------------------------------------
# set xtics 1
# set ytics 1
# set grid xtics ytics
# plot t,high_bit_pos(NaN)
# pause mouse
#------------------------------------------------------------------------------
# unset parametric
# # factorial(n) = gamma(int(n)+1)
#
# # plot from 0 to xmax
# # xmax = 4
# # set yrange [0:xmax!+1]
# # set bmargin 2
# # set ytics 0,2
#
#
# # Gnuplot has a builtin ! factorial operator for use on
# # integers.
#
# set xrange [0:4.95]
# set key left
# plot int(x)!
#
# # If you wanted to write your own it can be done recursively.
#
# # Using int(n) allows non-integer "n" inputs, with the factorial
# # calculated on int(n) in that case.
# # Arranging the condition as "n>=2" avoids infinite recursion if
# # n==NaN, since any comparison involving NaN is false. Could change
# # "1" to an expression like "n*0+1" to propagate a NaN input to the
# # output too, if desired.
# #
# factorial(n) = (n >= 2 ? int(n)*factorial(n-1) : 1)
# set xrange [0:4.95]
# set key left
# plot factorial(x)
#
# # plot (factorial(NaN))
# pause 100
#
# # And the gamma() function for any real.
#
# set xrange [0:5]
# plot gamma(x)
#------------------------------------------------------------------------------
# dragon_midpoint(n) = ((dragon(n) + dragon(n+1)) / {1,1} + {-0.5,0.5})
# set xtics 1
# set ytics 1
# # set mxtics 1
# set grid xtics ytics
# plot real(dragon_midpoint(t)),imag(dragon_midpoint(t)) with lines
pause 100 Math-PlanePath-113/devel/diagonals.pl 0000644 0001750 0001750 00000006437 12157255652 015320 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
use Math::PlanePath::Diagonals;
use Math::NumSeq::PlanePathDelta;
{
my $dir = 'up';
foreach my $y_start (reverse -7 .. 7) {
printf "Ystart=%2d", $y_start;
foreach my $x_start (-7 .. 7) {
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
printf " %3d", $seq->values_max;
}
print "\n";
}
print "\n";
foreach my $y_start (reverse -7 .. 7) {
printf "Ystart=%2d", $y_start;
foreach my $x_start (-7 .. 7) {
my $max = dsumabs_max($x_start,$y_start);
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
my $diff = ($seq->values_max == $max ? ' ' : '*');
printf "%3d%s", $max, $diff;
}
print "\n";
}
print "\n";
foreach my $y_start (reverse -7 .. 7) {
printf "Ystart=%2d", $y_start;
foreach my $x_start (-7 .. 7) {
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
printf " %3d", $seq->values_min;
}
print "\n";
}
print "\n";
foreach my $y_start (reverse -7 .. 7) {
printf "Ystart=%2d ", $y_start;
foreach my $x_start (-7 .. 7) {
my $min = dsumabs_min($x_start,$y_start);
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
my $diff = ($seq->values_min == $min ? ' ' : '*');
printf "%3d%s", $min, $diff;
}
print "\n";
}
print "\n";
exit 0;
sub dsumabs_min {
my ($x_start, $y_start) = @_;
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
my $i_start = $seq->i_start;
my $min = $seq->ith($i_start);
foreach my $i ($i_start .. 500) {
$min = min($min, $seq->ith($i));
}
return $min;
}
sub dsumabs_max {
my ($x_start, $y_start) = @_;
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => "Diagonals,x_start=$x_start,y_start=$y_start,direction=$dir",
delta_type => 'dSumAbs');
my $i_start = $seq->i_start;
my $max = $seq->ith($i_start);
foreach my $i ($i_start .. 500) {
$max = max($max, $seq->ith($i));
}
return $max;
}
}
Math-PlanePath-113/devel/ulam-warburton.pl 0000644 0001750 0001750 00000012027 12150576361 016322 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use warnings;
# uncomment this to run the ### lines
#use Smart::Comments;
{
require Math::PlanePath::UlamWarburton;
my $path = Math::PlanePath::UlamWarburton->new(parts=>1);
for (my $depth = 0; $depth < 35; $depth++) {
my $n = $path->tree_depth_to_n($depth);
my ($x,$y) = $path->n_to_xy($n);
my $rn = $path->xy_to_n($x,$y);
my $diff = $rn - $n;
print "$depth $n $x,$y $diff\n";
}
exit 0;
}
{
# height
# my $class = 'Math::PlanePath::UlamWarburton';
# my $class = 'Math::PlanePath::UlamWarburtonQuarter';
# my $class = 'Math::PlanePath::ToothpickUpist';
my $class = 'Math::PlanePath::LCornerTree';
eval "require $class";
require Math::BaseCnv;
my $path = $class->new (parts => 1);
my $prev_depth = 0;
for (my $n = $path->n_start;; $n++) {
my $depth = $path->tree_n_to_depth($n);
my $n_depth = $path->tree_depth_to_n($depth);
if ($depth != $prev_depth) {
print "\n";
last if $depth > 65;
$prev_depth = $depth;
}
my $calc_height = $path->tree_n_to_subheight($n);
my $search_height = path_tree_n_to_subheight_by_search($path,$n);
my $n3 = Math::BaseCnv::cnv($n - $n_depth, 10,3);
$search_height //= 'undef';
$calc_height //= 'undef';
my $diff = ($search_height eq $calc_height ? '' : ' ***');
printf "%2d %2d %3s %5s %5s%s\n",
$depth, $n, $n3, $search_height, $calc_height, $diff;
}
exit 0;
sub path_tree_n_to_subheight_by_search {
my ($self, $n) = @_;
my @n = ($n);
my $height = 0;
for (;;) {
@n = map {$self->tree_n_children($_)} @n
or return $height;
$height++;
if (@n > 400 || $height > 70) {
return undef; # presumed infinite
}
}
}
}
{
# number of children
require Math::PlanePath::UlamWarburton;
require Math::PlanePath::UlamWarburtonQuarter;
# my $path = Math::PlanePath::UlamWarburton->new;
my $path = Math::PlanePath::UlamWarburtonQuarter->new;
my $prev_depth = 0;
for (my $n = $path->n_start; ; $n++) {
my $depth = $path->tree_n_to_depth($n);
if ($depth != $prev_depth) {
$prev_depth = $depth;
print "\n";
last if $depth > 40;
}
my $num_children = $path->tree_n_num_children($n);
print "$num_children,";
}
print "\n";
exit 0;
}
# turn on u(0) = 1
# u(1) = 1
# u(n) = 4 * 3^ones(n-1) - 1
# where ones(x) = number of 1 bits A000120
#
{
my @yx;
sub count_around {
my ($x,$y) = @_;
return ((!! $yx[$y+1][$x])
+ (!! $yx[$y][$x+1])
+ ($x > 0 && (!! $yx[$y][$x-1]))
+ ($y > 0 && (!! $yx[$y-1][$x])));
}
my (@turn_x,@turn_y);
sub turn_on {
my ($x,$y) = @_;
### turn_on(): "$x,$y"
if (! $yx[$y][$x] && count_around($x,$y) == 1) {
push @turn_x, $x;
push @turn_y, $y;
}
}
my $print_grid = 1;
my $cumulative = 1;
my @lchar = ('a' .. 'z');
$yx[0][0] = $lchar[0];
for my $level (1 .. 20) {
print "\n";
printf "level %d %b\n", $level, $level;
if ($print_grid) {
foreach my $row (reverse @yx) {
foreach my $cell (@$row) {
print ' ', (defined $cell #&& ($cell eq 'p' || $cell eq 'o')
? $cell : ' ');
}
print "\n";
}
print "\n";
}
{
my $count = 0;
foreach my $row (reverse @yx) {
foreach my $cell (@$row) {
$count += defined $cell;
}
}
print "total $count\n";
}
foreach my $y (0 .. $#yx) {
my $row = $yx[$y];
foreach my $x (0 .. $#$row) {
$yx[$y][$x] or next;
### cell: $yx[$y][$x]
turn_on ($x, $y+1);
turn_on ($x+1, $y);
if ($x > 0) {
turn_on ($x-1, $y);
}
if ($y > 0) {
turn_on ($x, $y-1);
}
}
}
print "extra ",scalar(@turn_x),"\n";
my %seen_turn;
for (my $i = 0; $i < @turn_x; ) {
my $key = "$turn_x[$i],$turn_y[$i]";
if ($seen_turn{$key}) {
splice @turn_x,$i,1;
splice @turn_y,$i,1;
} else {
$seen_turn{$key} = 1;
$i++;
}
}
my $e = 4*(scalar(@turn_x)-2)+4;
$cumulative += $e;
print "extra $e cumulative $cumulative\n";
### @turn_x
### @turn_y
while (@turn_x) {
$yx[pop @turn_y][pop @turn_x] = ($lchar[$level]||'z');
}
### @yx
}
exit 0;
}
Math-PlanePath-113/devel/corner-replicate.pl 0000644 0001750 0001750 00000002261 12157300664 016576 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
use Math::PlanePath::CornerReplicate;
{
my $path = Math::PlanePath::CornerReplicate->new;
foreach my $n (0x0FFF, 0x1FFF, 0x2FFF, 0x3FFF) {
my ($x,$y) = $path->n_to_xy ($n);
my ($x2,$y2) = $path->n_to_xy ($n+1);
my $dsum = ($x2+$y2) - ($x+$y);
printf "%4X to %4X %2X,%2X to %2X,%2X dSum=%d\n",
$n,$n+1, $x,$y, $x2,$y2, $dsum;
}
exit 0;
}
Math-PlanePath-113/devel/terdragon.pl 0000644 0001750 0001750 00000044040 12224124247 015322 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
# # skip low zeros
# # 1 left
# # 2 right
# ones(n) - ones(n+1)
# 1*3^k left
# 2*3^k right
{
# dRadius range
my $n = 118088;
require Math::PlanePath::TerdragonMidpoint;
my $path = Math::PlanePath::TerdragonMidpoint->new;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
print "$x1,$y1 $x2,$y2\n";
exit 0;
}
{
# A+Yw A=X-Y
use lib 'xt'; require MyOEIS;
require Math::BaseCnv;
require Math::PlanePath::TerdragonCurve;
my $path = Math::PlanePath::TerdragonCurve->new;
my $dx_min = 0;
my $dx_max = 0;
foreach my $n (1 .. 3**10) {
my ($dx,$dy) = $path->n_to_dxdy($n);
if ($dx == 299) {
my $n3 = Math::BaseCnv::cnv($n,10,3);
printf "%3d %s\n", $n, $n3;
}
$dx_min = min($dx_min,$dx);
$dx_max = max($dx_max,$dx);
}
print "$dx_min $dx_max\n";
exit 0;
}
{
# A+Yw A=X-Y
use lib 'xt'; require MyOEIS;
require Math::PlanePath::TerdragonCurve;
require Math::BaseCnv;
my $path = Math::PlanePath::TerdragonCurve->new;
my @values;
foreach my $n (1 .. 3**6) {
my ($x,$y) = $path->n_to_xy($n);
my @n_list = $path->xy_to_n_list($x,$y);
if (@n_list == 1) {
push @values, $n;
}
if (@n_list == 1 && $n == $n_list[0]) {
my $n3 = Math::BaseCnv::cnv($n,10,3);
printf "%3d %s\n", $n, $n3;
}
}
print join(',',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
{
# A+Yw A=X-Y
use lib 'xt';
require MyOEIS;
require Math::PlanePath::TerdragonCurve;
my $path = Math::PlanePath::TerdragonCurve->new;
my @values;
foreach my $n (1 .. 20) {
my ($x,$y) = $path->n_to_xy($n);
push @values, ($x-$y);
}
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
{
# powers (1+w)^k
# w^2 = -1+w
# (a+bw)*(1+w) = a+bw + aw+bw^2
# = a + bw + aw - b + bw
# = (a-b) + (a+2b)w
# a+bw = (a+b) + bw^2
use lib 'xt';
require MyOEIS;
my $a = 1;
my $b = 0;
my @values;
for (1 .. 10) {
push @values, -($a+$b);
($a,$b) = ($a-$b, $a+2*$b);
}
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
{
# TerdragonCurve direction away from a point
require Image::Base::Text;
require Math::PlanePath::TerdragonCurve;
my $arms = 6;
my $path = Math::PlanePath::TerdragonCurve->new (arms => $arms);
my $width = 78;
my $height = 40;
my $x_lo = -$width/2;
my $y_lo = -$height/2;
my $x_hi = $x_lo + $width - 1;
my $y_hi = $y_lo + $height - 1;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my $plot = sub {
my ($x,$y,$char) = @_;
$x -= $x_lo;
$y -= $y_lo;
return if $x < 0 || $y < 0 || $x >= $width || $y >= $height;
$image->xy ($x,$height-1-$y,$char);
};
my ($n_lo, $n_hi) = $path->rect_to_n_range($x_lo-2,$y_lo-2, $x_hi+2,$y_hi+2);
print "n_hi $n_hi\n";
for my $n (0 .. $n_hi) {
my $arm = $n % $arms;
my ($x,$y) = $path->n_to_xy($n);
next if $x < $x_lo || $y < $y_lo || $x > $x_hi || $y > $y_hi;
my ($nx,$ny) = $path->n_to_xy($n + $arms);
my $dir = dxdy_to_dir6($nx-$x,$ny-$y);
if ($dir == 2) {
$plot->($x, $y, $dir);
}
}
$plot->(0,0, '+');
$image->save('/dev/stdout');
exit 0;
}
{
# TerdragonCurve xy_to_n offsets to Midpoint
require Math::PlanePath::TerdragonCurve;
require Math::PlanePath::TerdragonMidpoint;
my $arms = 6;
my $curve = Math::PlanePath::TerdragonCurve->new (arms => $arms);
my $midpoint = Math::PlanePath::TerdragonMidpoint->new (arms => $arms);
my %seen;
for my $n (0 .. 1000) {
my ($x,$y) = $curve->n_to_xy($n);
$x *= 2;
$y *= 2;
for my $dx (-2 .. 2) {
for my $dy (-1 .. 1) {
my $m = $midpoint->xy_to_n($x+$dx,$y+$dy) // next;
if ($m == $n) {
$seen{"$dx,$dy"} = 1;
}
}
}
}
### %seen
exit 0;
}
{
# TerdragonCurve xy cf Midpoint
require Image::Base::Text;
require Math::PlanePath::TerdragonCurve;
require Math::PlanePath::TerdragonMidpoint;
my $arms = 6;
my $curve = Math::PlanePath::TerdragonCurve->new (arms => $arms);
my $midpoint = Math::PlanePath::TerdragonMidpoint->new (arms => $arms);
my $width = 50;
my $height = 30;
my $x_lo = -$width/2;
my $y_lo = -$height/2;
my $x_hi = $x_lo + $width - 1;
my $y_hi = $y_lo + $height - 1;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my $plot = sub {
my ($x,$y,$char) = @_;
$x -= $x_lo;
$y -= $y_lo;
return if $x < 0 || $y < 0 || $x >= $width || $y >= $height;
$image->xy ($x,$height-1-$y,$char);
};
my ($n_lo, $n_hi) = $curve->rect_to_n_range($x_lo-2,$y_lo-2, $x_hi+2,$y_hi+2);
print "n_hi $n_hi\n";
for my $y ($y_lo .. $y_hi) {
for my $x ($x_lo .. $x_hi) {
my $n = $curve->xy_to_n($x,$y) // next;
my $arm = $n % $arms;
my ($nx,$ny) = $curve->n_to_xy($n + $arms);
my $dir = dxdy_to_dir6($nx-$x,$ny-$y);
$plot->($x, $y, $dir);
}
}
$plot->(0,0, '+');
$image->save('/dev/stdout');
exit 0;
}
{
# TerdragonMidpoint xy absolute direction
require Image::Base::Text;
require Math::PlanePath::TerdragonMidpoint;
my $arms = 6;
my $path = Math::PlanePath::TerdragonMidpoint->new (arms => $arms);
my $width = 50;
my $height = 30;
my $x_lo = -$width/2;
my $y_lo = -$height/2;
my $x_hi = $x_lo + $width - 1;
my $y_hi = $y_lo + $height - 1;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my $plot = sub {
my ($x,$y,$char) = @_;
$x -= $x_lo;
$y -= $y_lo;
return if $x < 0 || $y < 0 || $x >= $width || $y >= $height;
$image->xy ($x,$height-1-$y,$char);
};
my ($n_lo, $n_hi) = $path->rect_to_n_range($x_lo-2,$y_lo-2, $x_hi+2,$y_hi+2);
print "n_hi $n_hi\n";
for my $n (0 .. $n_hi) {
my $arm = $n % $arms;
my ($x,$y) = $path->n_to_xy($n);
# if (($n % $arms) == 1) {
# $x += 1;
# $y += 1;
# }
next if $x < $x_lo || $y < $y_lo || $x > $x_hi || $y > $y_hi;
my ($nx,$ny) = $path->n_to_xy($n + $arms);
# if (($n % $arms) == 1) {
# $nx += 1;
# $ny += 1;
# }
# if ($nx == $x+1) {
# $image->xy($x,$y,$n&3);
# }
# if ($ny == $y+1) {
# $image->xy($x,$y,$n&3);
# }
# if ($ny == $y) {
# }
my $show;
my $dir = dxdy_to_dir6($nx-$x,$ny-$y);
my $digit = (($x + 3*$y) + 0) % 3;
my $d9 = ((2*$x + $y) + 0) % 9;
my $c = ($x+$y)/2;
my $flow = sprintf "%X", ($x + 3*$y) % 12;
my $prev_dir = -1;
if ($n >= $arms) {
my ($px,$py) = $path->n_to_xy($n - $arms);
$prev_dir = dxdy_to_dir6($x-$px,$y-$py);
}
foreach my $r (0,1,2) {
$flow = ($r == 0 ? '-'
: $r == 1 ? '/'
: '\\');
if ($arm & 1) {
if (($digit == 0 || $digit == 1)
&& (($dir%3) == $r)) {
$show = $flow;
}
if (($digit == 2)
&& (($prev_dir%3) == $r)) {
$show = $flow;
}
} else {
if (($digit == 0 || $digit == 2)
&& (($dir%3) == $r)) {
$show = $flow;
}
if (($digit == 1)
&& (($prev_dir%3) == $r)) {
$show = $flow;
}
}
}
if (! defined $show) {
$show = '.';
}
# if ($digit == 1) {
# if ($dir == 0 || $dir == 3) {
# $show = $dir;
# $show = 'x';
# }
# }
# if ($digit == 2) {
# if ($dir == 0 || $dir == 3) {
# $show = $prev_dir;
# $show = 'x';
# }
# }
# if ($digit == 0) {
# $show = 'x';
# }
my $mod = (int($n/$arms) % 3);
# if (($arm == 0 && $mod == 0)
# || ($arm == 1 && $mod == 2)
# || ($arm == 2 && $mod == 0)
# || ($arm == 3 && $mod == 2)
# || ($arm == 4 && $mod == 0)
# || ($arm == 5 && $mod == 2)) {
# # $show = '0';
# # $show = $digit;
# if ($n < 3*$arms) {
# print "n=$n $x,$y mod=$mod\n";
# }
# }
# if (($arm == 0 && $mod == 1)
# || ($arm == 1 && $mod == 1)
# || ($arm == 2 && $mod == 1)
# || ($arm == 3 && $mod == 1)
# || ($arm == 4 && $mod == 1)
# || ($arm == 5 && $mod == 1)) {
# # $show = '1';
# }
# if (($arm == 0 && $mod == 2)
# || ($arm == 1 && $mod == 0)
# || ($arm == 2 && $mod == 2)
# || ($arm == 3 && $mod == 0)
# || ($arm == 4 && $mod == 2)
# || ($arm == 5 && $mod == 0)) {
# # $show = '2';
# }
if (defined $show) {
$plot->($x, $y, $show);
}
# if ($dir == 0) {
# $image->xy($x-$x_lo,$y-$y_lo, $dir);
# }
}
# $plot->(0,0, '+');
$image->save('/dev/stdout');
exit 0;
}
{
require Math::PlanePath::TerdragonMidpoint;
my $path = Math::PlanePath::TerdragonMidpoint->new;
$path->xy_to_n(5,3);
exit 0;
}
{
# TerdragonMidpoint modulo
require Math::PlanePath::TerdragonMidpoint;
my $arms = 2;
my $path = Math::PlanePath::TerdragonMidpoint->new (arms => $arms);
for my $n (0 .. 3**4) {
my $arm = $n % $arms;
my $mod = (int($n/$arms) % 3);
my ($x,$y) = $path->n_to_xy($n);
my $digit = (($x + 3*$y) + 0) % 3;
print "n=$n $x,$y mod=$mod k=$digit\n";
}
exit 0;
}
{
# cumulative turn +/- 1 list
require Math::PlanePath::TerdragonCurve;
require Math::BaseCnv;
my $path = Math::PlanePath::TerdragonCurve->new;
my $cumulative = 0;
for (my $n = $path->n_start + 1; $n < 35; $n++) {
my $n3 = Math::BaseCnv::cnv($n,10,3);
my $turn = calc_n_turn ($n);
# my $turn = path_n_turn($path, $n);
if ($turn == 2) { $turn = -1 }
$cumulative += $turn;
printf "%3s %4s %d\n", $n, $n3, $cumulative;
}
print "\n";
exit 0;
}
{
# cumulative turn +/- 1
require Math::PlanePath::TerdragonCurve;
my $path = Math::PlanePath::TerdragonCurve->new;
my $cumulative = 0;
my $max = 0;
my $min = 0;
for (my $n = $path->n_start + 1; $n < 35; $n++) {
my $turn = calc_n_turn ($n);
# my $turn = path_n_turn($path, $n);
if ($turn == 2) { $turn = -1 }
$cumulative += $turn;
$max = max($cumulative,$max);
$min = min($cumulative,$min);
print "$cumulative,";
}
print "\n";
print "min $min max $max\n";
exit 0;
sub calc_n_turn {
my ($n) = @_;
die if $n == 0;
while (($n % 3) == 0) {
$n = int($n/3); # skip low 0s
}
return ($n % 3); # next digit is the turn
}
}
{
# turn
require Math::PlanePath::TerdragonCurve;
my $path = Math::PlanePath::TerdragonCurve->new;
my $n = $path->n_start;
# my ($n0_x, $n0_y) = $path->n_to_xy ($n);
# $n++;
# my ($prev_x, $prev_y) = $path->n_to_xy ($n);
# my ($prev_dx, $prev_dy) = ($prev_x - $n0_x, $prev_y - $n0_y);
# my $prev_dir = dxdy_to_dir ($prev_dx, $prev_dy);
$n++;
my $pow = 3;
for ( ; $n < 128; $n++) {
# my ($x, $y) = $path->n_to_xy ($n);
# my $dx = $x - $prev_x;
# my $dy = $y - $prev_y;
# my $dir = dxdy_to_dir ($dx, $dy);
# my $turn = ($dir - $prev_dir) % 3;
#
# $prev_dir = $dir;
# ($prev_x,$prev_y) = ($x,$y);
my $turn = path_n_turn($path, $n);
my $azeros = digit_above_low_zeros($n);
my $azx = ($azeros == $turn ? '' : '*');
# my $aones = digit_above_low_ones($n-1);
# if ($aones==0) { $aones=1 }
# elsif ($aones==1) { $aones=0 }
# elsif ($aones==2) { $aones=2 }
# my $aox = ($aones == $turn ? '' : '*');
#
# my $atwos = digit_above_low_twos($n-2);
# if ($atwos==0) { $atwos=1 }
# elsif ($atwos==1) { $atwos=2 }
# elsif ($atwos==2) { $atwos=0 }
# my $atx = ($atwos == $turn ? '' : '*');
#
# my $lzero = digit_above_low_zeros($n);
# my $lone = digit_above_lowest_one($n);
# my $ltwo = digit_above_lowest_two($n);
# print "$n $turn ones $aones$aox twos $atwos$atx zeros $azeros${azx}[$lzero] $lone $ltwo\n";
print "$n $turn zeros got=$azeros ${azx}\n";
}
print "\n";
exit 0;
sub digit_above_low_zeros {
my ($n) = @_;
if ($n == 0) {
return 0;
}
while (($n % 3) == 0) {
$n = int($n/3);
}
return ($n % 3);
}
sub path_n_turn {
my ($path, $n) = @_;
my $prev_dir = path_n_dir ($path, $n-1);
my $dir = path_n_dir ($path, $n);
return ($dir - $prev_dir) % 3;
}
sub path_n_dir {
my ($path, $n) = @_;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
my ($x, $y) = $path->n_to_xy ($n+1);
return dxdy_to_dir($x - $prev_x, $y - $prev_y);
}
}
{
# min/max for level
require Math::PlanePath::TerdragonCurve;
require Math::BaseCnv;
my $path = Math::PlanePath::TerdragonCurve->new;
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 25; $level++) {
my $n_start = 3**($level-1);
my $n_end = 3**$level;
my $min_hypot = 128*$n_end*$n_end;
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + 3*$y*$y;
if ($h < $min_hypot) {
$min_hypot = $h;
$min_pos = "$x,$y";
}
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $prev_min;
my $min_hypot3 = Math::BaseCnv::cnv($min_hypot,10,3);
print " min h= $min_hypot [$min_hypot3] at $min_pos factor $factor\n";
my $calc = (4/3/3) * 2.9**$level;
print " cf $calc\n";
}
# {
# my $factor = $max_hypot / $prev_max;
# my $max_hypot3 = Math::BaseCnv::cnv($max_hypot,10,3);
# print " max h= $max_hypot [$max_hypot3] at $max_pos factor $factor\n";
# # my $calc = 4 * 3**($level*.9) * 4**($level*.1);
# # print " cf $calc\n";
# }
$prev_min = $min_hypot;
$prev_max = $max_hypot;
}
exit 0;
}
{
# triplications
require Math::PlanePath::TerdragonCurve;
require Math::BaseCnv;
my $path = Math::PlanePath::TerdragonCurve->new;
my %seen;
for (my $n = 0; $n < 2000; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $key = "$x,$y";
push @{$seen{$key}}, $n;
if (@{$seen{$key}} == 3) {
my @v3;
foreach my $v (@{delete $seen{$key}}) {
my $v3 = Math::BaseCnv::cnv($v,10,3);
push @v3, $v3;
printf "%4s %7s\n", $v, $v3;
}
my $lenmatch = 0;
foreach my $i (1 .. length($v3[0])) {
my $want = substr ($v3[0], -$i);
if ($v3[1] =~ /$want$/ && $v3[2] =~ /$want$/) {
next;
} else {
$lenmatch = $i-1;
last;
last;
}
}
my $zeros = ($v3[0] =~ /(0*)$/ && $1);
my $lenzeros = length($zeros);
my $same = ($lenmatch == $lenzeros+1 ? "same" : "diff");
print "low same $lenmatch zeros $lenzeros $same\n";
print "\n";
}
}
exit 0;
}
{
# turn
require Math::PlanePath::TerdragonCurve;
my $path = Math::PlanePath::TerdragonCurve->new;
my $n = $path->n_start;
my ($n0_x, $n0_y) = $path->n_to_xy ($n);
$n++;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
my ($prev_dx, $prev_dy) = ($prev_x - $n0_x, $prev_y - $n0_y);
my $prev_dir = dxdy_to_dir ($prev_dx, $prev_dy);
$n++;
my $pow = 3;
for ( ; $n < 128; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my $dx = ($x - $prev_x);
my $dy = ($y - $prev_y);
my $dir = dxdy_to_dir ($dx, $dy);
my $turn = ($dir - $prev_dir) % 3;
$prev_dir = $dir;
($prev_x,$prev_y) = ($x,$y);
print "$turn";
if ($n-1 == $pow) {
$pow *= 3;
print "\n";
}
}
print "\n";
exit 0;
}
sub path_to_dir6 {
my ($path,$n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my ($nx,$ny) = $path->n_to_xy($n + $path->arms_count);
return dxdy_to_dir6($nx-$x,$ny-$y);
}
sub dxdy_to_dir6 {
my ($dx,$dy) = @_;
if ($dy == 0) {
if ($dx == 2) { return 0; }
if ($dx == -2) { return 3; }
}
if ($dy == 1) {
if ($dx == 1) { return 1; }
if ($dx == -1) { return 2; }
}
if ($dy == -1) {
if ($dx == 1) { return 5; }
if ($dx == -1) { return 4; }
}
die "unrecognised $dx,$dy";
}
# per KochCurve.t
sub dxdy_to_dir {
my ($dx,$dy) = @_;
if ($dy == 0) {
if ($dx == 2) { return 0/2; }
# if ($dx == -2) { return 3; }
}
if ($dy == 1) {
# if ($dx == 1) { return 1; }
if ($dx == -1) { return 2/2; }
}
if ($dy == -1) {
# if ($dx == 1) { return 5; }
if ($dx == -1) { return 4/2; }
}
die "unrecognised $dx,$dy";
}
sub digit_above_low_ones {
my ($n) = @_;
if ($n == 0) {
return 0;
}
while (($n % 3) == 1) {
$n = int($n/3);
}
return ($n % 3);
}
sub digit_above_low_twos {
my ($n) = @_;
if ($n == 0) {
return 0;
}
while (($n % 3) == 2) {
$n = int($n/3);
}
return ($n % 3);
}
sub digit_above_lowest_zero {
my ($n) = @_;
for (;;) {
if (($n % 3) == 0) {
last;
}
$n = int($n/3);
}
$n = int($n/3);
return ($n % 3);
}
sub digit_above_lowest_one {
my ($n) = @_;
for (;;) {
if (! $n || ($n % 3) != 0) {
last;
}
$n = int($n/3);
}
$n = int($n/3);
return ($n % 3);
}
sub digit_above_lowest_two {
my ($n) = @_;
for (;;) {
if (! $n || ($n % 3) != 0) {
last;
}
$n = int($n/3);
}
$n = int($n/3);
return ($n % 3);
}
Math-PlanePath-113/devel/cellular-rule-oeis.pl 0000644 0001750 0001750 00000005673 11712574703 017062 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use HTML::Entities::Interpolate;
use List::Util;
use URI::Escape;
use Tie::IxHash;
use Math::BigInt;
use Math::PlanePath::CellularRule;
# uncomment this to run the ### lines
#use Smart::Comments;
open OUT, ">/tmp/find.html" or die;
print OUT <start
HERE
{
# 0/1 cells
my %done;
tie %done, 'Tie::IxHash';
foreach my $rule (0 .. 255) {
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my @values;
Y01: foreach my $y (0 .. 10) {
foreach my $x (-$y .. $y) {
if (defined ($path->xy_to_n($x,$y))) {
push @values, 1;
} else {
push @values, 0;
}
last Y01 if (@values > 30);
}
}
my $values = join(',',@values);
$done{$values} .= ",$rule";
}
foreach my $values (keys %done) {
my $name = $done{$values};
$name =~ s/^,//;
my $values_escaped = URI::Escape::uri_escape($values);
print OUT " \n0/1 rule=$name\n" or die;
print OUT <$values
HERE
}
print OUT "
\n" or die;
}
{
# bignum rows
my %done;
tie %done, 'Tie::IxHash';
foreach my $rule (0 .. 255) {
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my @values;
Y01: foreach my $y (0 .. 10) {
my $n = Math::BigInt->new(0);
foreach my $x (-$y .. $y) {
$n *= 2;
if (defined ($path->xy_to_n($x,$y))) {
$n++;
}
push @values, $n;
last Y01 if (@values > 30);
}
}
my $values = join(',',@values);
$done{$values} .= ",$rule";
}
foreach my $values (keys %done) {
my $name = $done{$values};
$name =~ s/^,//;
my $values_escaped = URI::Escape::uri_escape($values);
print OUT " \n0/1 rule=$name\n" or die;
print OUT <$values
HERE
}
print OUT "\n" or die;
}
print OUT <
HERE
close OUT or die;
exit 0;
Math-PlanePath-113/devel/sierpinski-triangle.pl 0000644 0001750 0001750 00000017251 12204065463 017326 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::SierpinskiTriangle;
use Math::PlanePath;
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
# uncomment this to run the ### lines
use Smart::Comments;
{
# number of children
my $path = Math::PlanePath::SierpinskiTriangle->new;
for (my $n = $path->n_start; $n < 180; $n++) {
my @n_children = $path->tree_n_children($n);
my $num_children = scalar(@n_children);
print "$num_children,";
print "\n" if path_tree_n_is_depth_end($path,$n);
}
print "\n";
exit 0;
sub path_tree_n_is_depth_end {
my ($path, $n) = @_;
my $depth = $path->tree_n_to_depth($n);
return defined($depth) && $n == $path->tree_depth_to_n_end($depth);
}
}
{
# Pascal's triangle
require Math::BigInt;
my @array;
my $rows = 10;
my $width = 0;
foreach my $y (0 .. $rows) {
foreach my $x (0 .. $y) {
my $n = Math::BigInt->new($y);
my $k = Math::BigInt->new($x);
$n->bnok($k);
my $str = "$n";
$array[$x][$y] = $str;
$width = max($width,length($str));
}
}
$width += 2;
if ($width & 1) { $width++; }
# $width |= 1;
foreach my $y (0 .. $rows) {
print ' ' x (($rows-$y) * int($width/2));
foreach my $x (0 .. $y) {
my $value = $array[$x][$y];
unless ($value & 1) { $value = ''; }
printf "%*s", $width, $value;
}
print "\n";
}
exit 0;
}
{
# NumSiblings run lengths
# lowest 1-bit of pos k
# NumChildren run lengths
# is same lowest 1-bit if NumChildren=0 leaf coalesced with NumChildren=1
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'diagonal');
require Math::NumSeq::PlanePathCoord;
my $seq = Math::NumSeq::PlanePathCoord->new (planepath_object => $path,
# coordinate_type => 'NumChildren',
coordinate_type => 'NumSiblings',
);
my $prev = 0;
my $run = 1;
for (my $n = $path->n_start+1; $n < 500; $n++) {
my ($i,$value) = $seq->next;
$value = 1-$value;
# if ($value == 1) { $value = 0; }
# if ($value == $prev) {
# $run++;
# } else {
# print "$run,";
# $run = 1;
# $prev = $value;
# }
# printf "%4b %d\n", $i, $value;
print "$value,";
}
print "\n";
exit 0;
sub path_tree_n_num_siblings {
my ($path, $n) = @_;
$n = $path->tree_n_parent($n);
return (defined $n
? $path->tree_n_num_children($n) - 1 # not including self
: 0); # any tree root considered to have no siblings
}
}
{
# height
use constant _INFINITY => do {
my $x = 999;
foreach (1 .. 20) {
$x *= $x;
}
$x;
};
my $path = Math::PlanePath::SierpinskiTriangle->new (align => 'diagonal');
require Math::NumSeq::PlanePathCoord;
my $seq = Math::NumSeq::PlanePathCoord->new (planepath_object => $path,
coordinate_type => 'SubHeight');
for (my $n = $path->n_start; $n < 500; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $s = $seq->ith($n);
# my $c = $path->_UNTESTED__NumSeq__tree_n_to_leaflen($n);
my $c = n_to_subheight($n);
if (! defined $c) { $c = _INFINITY; }
my $diff = ($s == $c ? '' : ' ***');
print "$x,$y $s $c$diff\n";
}
print "\n";
exit 0;
sub n_to_subheight {
my ($n) = @_;
# this one correct based on diagonal X,Y bits
my ($x,$y) = $path->n_to_xy($n);
if ($x == 0 || $y == 0) {
return _INFINITY();
}
my $mx = ($x ^ ($x-1)) >> 1;
my $my = ($y ^ ($y-1)) >> 1;
return max ($mx - ($y & $mx),
$my - ($x & $my));
# Must stretch out $n remainder to make X.
# my ($depthbits, $ndepth, $nwidth) = Math::PlanePath::SierpinskiTriangle::_n0_to_depthbits($n);
# $n -= $ndepth; # X
# my $y = digit_join_lowtohigh ($depthbits, 2, $n*0) - $n;
#
# if ($n == 0 || $y == 0) {
# return undef;
# }
# my $mx = ($n ^ ($n-1)) >> 1;
# my $my = ($y ^ ($y-1)) >> 1;
# return max ($mx - ($y & $mx),
# $my - ($n & $my));
# my $h = high_bit($y);
# my $m = ($h<<1)-1;
# return $y ^ $m;
# # return count_0_bits($y); # - count_0_bits($x);
}
sub high_bit {
my ($n) = @_;
my $bit = 1;
while ($bit <= $n) {
$bit <<= 1;
}
return $bit >> 1;
}
sub count_0_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1) ^ 1;
$n >>= 1;
}
return $count;
}
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
}
{
# number of children in replicate style
my $levels = 5;
my $height = 2**$levels;
sub replicate_n_to_xy {
my ($n) = @_;
my $zero = $n * 0;
my @xpos_bits;
my @xneg_bits;
my @y_bits;
foreach my $ndigit (digit_split_lowtohigh($n,3)) {
if ($ndigit == 0) {
push @xpos_bits, 0;
push @xneg_bits, 0;
push @y_bits, 0;
} elsif ($ndigit == 1) {
push @xpos_bits, 0;
push @xneg_bits, 1;
push @y_bits, 1;
} else {
push @xpos_bits, 1;
push @xneg_bits, 0;
push @y_bits, 1;
}
}
return (digit_join_lowtohigh(\@xpos_bits, 2, $zero)
- digit_join_lowtohigh(\@xneg_bits, 2, $zero),
digit_join_lowtohigh(\@y_bits, 2, $zero));
}
# xxx0 = 2 low digit 0 then num children = 2
# xxx0111 = 1 \ low digit != 0 then all low non-zeros must be same
# xxx0222 = 1 /
# other = 0 otherwise num children = 0
sub replicate_tree_n_num_children {
my ($n) = @_;
$n = int($n);
my $low_digit = _divrem_mutate($n,3);
if ($low_digit == 0) {
return 2;
}
while (my $digit = _divrem_mutate($n,3)) {
if ($digit != $low_digit) {
return 0;
}
}
return 1;
}
my $path = Math::PlanePath::SierpinskiTriangle->new;
my %grid;
for (my $n = 0; $n < 3**$levels; $n++) {
my ($x,$y) = replicate_n_to_xy($n);
my $path_num_children = path_xy_num_children($path,$x,$y);
my $repl_num_children = replicate_tree_n_num_children($n);
if ($path_num_children != $repl_num_children) {
print "$x,$y $path_num_children $repl_num_children\n";
exit 1;
}
$grid{$x}{$y} = $repl_num_children;
}
foreach my $y (0 .. $height) {
foreach my $x (-$height .. $y) {
print $grid{$x}{$y} // ' ';
}
print "\n";
}
exit 0;
sub path_xy_num_children {
my ($path, $x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
return (defined $n
? $path->tree_n_num_children($n)
: undef);
}
}
{
my $path = Math::PlanePath::SierpinskiTriangle->new;
foreach my $y (0 .. 10) {
foreach my $x (-$y .. $y) {
if ($path->xy_to_n($x,$y)) {
print "1,";
} else {
print "0,";
}
}
}
print "\n";
exit 0;
}
Math-PlanePath-113/devel/triangule-spiral.pl 0000644 0001750 0001750 00000003205 12154513447 016623 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
# uncomment this to run the ### lines
# use Smart::Comments;
{
# A010054 turn seq with Language::Logo
require Math::NumSeq::OEIS;
my $seq = Math::NumSeq::OEIS->new(anum=>'A010054');
# $seq->next;
require Language::Logo;
my $lo = Logo->new(update => 20, port=>8222);
$lo->command("seth 0; forward 50; pendown; forward 200; backward 200; penup; backward 50; pendown");
for (;;) {
logo_blob(5);
my ($i,$value) = $seq->next;
$lo->command("left ".($value*120));
if ($i > 0) {
}
$lo->command("forward 30");
}
$lo->disconnect("Finished...");
exit 0;
sub logo_blob {
my ($size) = @_;
my $half = $size/2;
$lo->command("
penup; forward $half; pendown;
left 90; forward $half;
left 90; forward $size;
left 90; forward $size;
left 90; forward $size;
left 90; forward $half;
right 90;
penup; backward $half; pendown
");
}
}
Math-PlanePath-113/devel/fibonacci-word.pl 0000644 0001750 0001750 00000016317 12150501071 016221 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
# uncomment this to run the ### lines
use Smart::Comments;
{
# Knot overlapping points
# 0,1, 4,16,68,288,1220,5168
# /4 1,4,17,72,305,1292 = A001076 a(n) = 4a(n-1) + a(n-2)
# denom continued fract converg to sqrt(5), 4-Fibonacci
# each next = this*4 + prev
require Math::PlanePath::FibonacciWordKnott;
require Math::BaseCnv;
require Math::NumSeq::BalancedBinary;
my $path = Math::PlanePath::FibonacciWordKnott->new;
my %seen;
my %diffs; require Tie::IxHash; tie %diffs, 'Tie::IxHash';
foreach my $n ($path->n_start .. 10000) {
my ($x,$y) = $path->n_to_xy($n);
if (my $p = $seen{$x,$y}) {
my $d = $n - $p;
# print "$x,$y $p $n diff $d\n";
$diffs{$d} ||= 1;
}
$seen{$x,$y} = $n;
}
my $bal = Math::NumSeq::BalancedBinary->new;
foreach my $d (keys %diffs) {
my $b = Math::BaseCnv::cnv($d,10,2);
my $z = $bal->ith($d);
$z = Math::BaseCnv::cnv($z,10,2);
print "$d bin=$b zeck=$z\n";
}
exit 0;
}
{
# Dense Fibonacci Word turns
require Math::NumSeq::FibonacciWord;
require Image::Base::Text;
my $image = Image::Base::Text->new (-width => 79, -height => 40);
my $foreground = '*';
my $doubleground = '+';
# require Image::Base::GD;
# $image = Image::Base::GD->new (-width => 200, -height => 200);
# $image->rectangle (0,0, 200,200, 'black');
# $foreground = 'white';
# $doubleground = 'red';
my $seq = Math::NumSeq::FibonacciWord->new (fibonacci_word_type => 'dense');
my $dx = 1;
my $dy = 0;
my $x = 1;
my $y = 1;
my $transpose = 1;
my $char = sub {
if ($transpose) {
if (($image->xy($y,$x)//' ') eq $foreground) {
$image->xy ($y,$x, $doubleground);
} else {
$image->xy ($y,$x, $foreground);
}
} else {
if (($image->xy($x,$y)//' ') eq $foreground) {
$image->xy ($x,$y, $doubleground);
} else {
$image->xy ($x,$y, $foreground);
}
}
};
my $draw = sub {
&$char ($x,$y);
$x += $dx;
$y += $dy;
&$char ($x,$y);
$x += $dx;
$y += $dy;
# &$char ($x,$y);
# $x += $dx;
# $y += $dy;
};
my $natural = sub {
my ($value) = @_;
&$draw();
if ($value == 1) {
($dx,$dy) = (-$dy,$dx);
} elsif ($value == 2) {
($dx,$dy) = ($dy,-$dx);
}
};
my $apply;
$apply = sub {
# dfw natural, rot +45
my ($i, $value) = $seq->next;
&$natural($value);
};
# # plus, rot -45
# $apply = sub {
# my ($i, $value) = $seq->next;
# if ($value == 0) {
# # empty
# } else {
# &$natural($value);
# }
# };
# $x += 20;
# $y += 20;
$apply = sub {
# standard
my ($i, $value) = $seq->next;
if ($value == 0) {
&$natural(1);
&$natural(2);
} elsif ($value == 1) {
&$natural(1);
&$natural(0);
} else {
&$natural(0);
&$natural(2);
}
};
# $x += 2;
# $y += int ($image->get('-height') / 2);
# $apply = sub {
# # rot pi/5 = 36deg curly
# my ($i, $value) = $seq->next;
# if ($value == 0) {
# &$natural(2);
# &$natural(1);
# } elsif ($value == 1) {
# &$natural(0);
# &$natural(2);
# } else {
# &$natural(1);
# &$natural(0);
# }
# };
# $x += 20;
# $y += 20;
$apply = sub {
# expanded
my ($i, $value) = $seq->next;
if ($value == 0) {
&$natural(0);
&$natural(1);
&$natural(0);
&$natural(2);
} elsif ($value == 1) {
&$natural(0);
&$natural(1);
&$natural(0);
} else {
&$natural(0);
&$natural(0);
&$natural(2);
}
};
$apply = sub {
# Ron Knott
my ($i, $value) = $seq->next;
if ($value == 0) {
&$natural(1);
&$natural(2);
} else {
&$natural($value);
}
};
print "$x,$y\n";
for (1 .. 2000) {
&$apply();
}
# $image->save('/tmp/x.png');
# system('xzgv /tmp/x.png');
my $lines = $image->save_string;
my @lines = split /\n/, $lines;
$, = "\n";
print reverse @lines;
exit 0;
}
{
my @xend = (0,0,1);
my @yend = (0,1,1);
my $f0 = 1;
my $f1 = 2;
my $level = 1;
my $transpose = 0;
my $rot = 0;
### at: "$xend[-1],$xend[-1] for $f1"
foreach (1 .. 20) {
($f1,$f0) = ($f1+$f0,$f1);
my $six = $level % 6;
$transpose ^= 1;
my ($x,$y);
if (($level % 6) == 0) {
$x = $yend[-2]; # T
$y = $xend[-2];
} elsif (($level % 6) == 1) {
$x = $yend[-2]; # -90
$y = - $xend[-2];
} elsif (($level % 6) == 2) {
$x = $xend[-2]; # T -90
$y = - $yend[-2];
} elsif (($level % 6) == 3) {
### T
$x = $yend[-2]; # T
$y = $xend[-2];
} elsif (($level % 6) == 4) {
$x = - $yend[-2]; # +90
$y = $xend[-2];
} elsif (($level % 6) == 5) {
$x = - $xend[-2]; # T +90
$y = $yend[-2];
}
push @xend, $xend[-1] + $x;
push @yend, $yend[-1] + $y;
### new: ($level%6)." add $x,$y for $xend[-1],$yend[-1] for $f1"
$level++;
}
exit 0;
}
{
my @xend = (0, 1);
my @yend = (1, 1);
my $f0 = 1;
my $f1 = 2;
foreach (1 .. 10) {
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $yend[-2], $yend[-1] + $xend[-2]); # T
push @xend, $nx;
push @yend, $ny;
### new 1: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $xend[-2], $yend[-1] - $yend[-2]); # T ...
push @xend, $nx;
push @yend, $ny;
### new 2: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $yend[-2], $yend[-1] + $xend[-2]); # T
push @xend, $nx;
push @yend, $ny;
### new 3: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $yend[-2], $yend[-1] + $xend[-2]); # T
push @xend, $nx;
push @yend, $ny;
### new 1b: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] - $xend[-2], $yend[-1] + $yend[-2]); # T +90
push @xend, $nx;
push @yend, $ny;
### new 2b: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $yend[-2], $yend[-1] + $xend[-2]); # T
push @xend, $nx;
push @yend, $ny;
### new 1c: "$nx, $ny for $f1"
}
{
($f1,$f0) = ($f1+$f0,$f1);
my ($nx,$ny) = ($xend[-1] + $yend[-2], $yend[-1] - $xend[-2]); # rot -90
push @xend, $nx;
push @yend, $ny;
### new 2c: "$nx, $ny for $f1"
}
}
exit 0;
}
Math-PlanePath-113/devel/bignums.pl 0000644 0001750 0001750 00000005765 12136655673 015032 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use POSIX ();
# uncomment this to run the ### lines
use Devel::Comments;
# my $inf = 2**99999;
# my $nan = $inf/$inf;
# print "$inf, $nan","\n";
# print $nan==$nan,"\n";
# print $nan<=>0,"\n";
# print 0<=>$nan,"\n";
{
use Math::BigFloat;
Math::BigFloat->accuracy(15);
my $n = Math::BigFloat->new(1);
$n->accuracy(50);
$n->batan2(.00000000, 100);
print "$n\n";
exit 0;
}
{
use Math::BigFloat;
my $n = Math::BigFloat->new('1.234567892345678923456789');
$n->accuracy(15);
# my $pi = $n->bpi(undef);
# my $pi = Math::BigFloat->bpi;
$n = Math::BigFloat->new(1);
print "$n\n";
$n->accuracy(10);
my $pi = $n->batan2(.0000001);
print "$pi\n";
exit 0;
}
{
use Math::BigFloat;
# Math::BigFloat->precision(5);
# Math::BigFloat->precision(-5);
Math::BigFloat->accuracy(13);
# my $n = Math::BigFloat->new('123456789.987654321');
my $n = Math::BigFloat->bpi(50);
print "$n\n";
exit 0;
}
{
use Math::BigFloat;
my $n = Math::BigFloat->new(1234);
### accuracy: $n->accuracy()
### precision: $n->precision()
my $global_accuracy = Math::BigFloat->accuracy();
my $global_precision = Math::BigFloat->precision();
### $global_accuracy
### $global_precision
my $global_div_scale = Math::BigFloat->div_scale();
### $global_div_scale
Math::BigFloat->div_scale(500);
$global_div_scale = Math::BigFloat->div_scale();
### $global_div_scale
### div_scale: $n->div_scale
$n = Math::BigFloat->new(1234);
### div_scale: $n->div_scale
exit 0;
}
{
require Math::Complex;
my $c = Math::Complex->new(123);
### $c
print $c,"\n";
print $c * 0,"\n";;
### int: int($c)
print int($c),"\n";;
exit 0;
}
{
require Math::BigRat;
use Math::BigFloat;
Math::BigFloat->precision(2000); # digits right of decimal point
Math::BigFloat->accuracy(2000);
{
my $x = Math::BigRat->new('1/2') ** 512;
print "$x\n";
my $r = sqrt($x);
print "$r\n";
print $r*$r,"\n";
# my $r = 8*$x-3;
# print "$r\n";
}
exit 0;
{
my $x = Math::BigInt->new(2) ** 128 - 1;
print "$x\n";
my $r = 8*$x-3;
print "$r\n";
}
{
my $x = Math::BigRat->new('100000000000000000000'.('0'x200));
$x = $x*$x-1;
print "$x\n";
my $r = sqrt($x);
print "$r\n";
$r = int($r);
print "$r\n";
}
}
Math-PlanePath-113/devel/tree.pl 0000644 0001750 0001750 00000014031 11765112630 014273 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX qw(floor ceil);
use List::Util qw(min max);
use Module::Load;
use App::MathImage::LinesTree;
# uncomment this to run the ### lines
#use Smart::Comments;
{
my $path_class;
require Math::PlanePath::Hypot;
require Math::PlanePath::HypotOctant;
require Math::PlanePath::PythagoreanTree;
require Math::PlanePath::GreekKeySpiral;
require Math::PlanePath::PixelRings;
require Math::PlanePath::TriangularHypot;
require Math::PlanePath::Diagonals;
require Math::PlanePath::SquareArms;
require Math::PlanePath::CellularRule54;
require Math::PlanePath::SquareReplicate;
require Math::PlanePath::KochSquareflakes;
require Math::PlanePath::SierpinskiTriangle;
require Math::PlanePath::DivisibleColumns;
require Math::PlanePath::DiamondSpiral;
require Math::PlanePath::DigitGroups;
require Math::PlanePath::DekkingCurve;
require Math::PlanePath::DekkingStraight;
require Math::PlanePath::HilbertCurve;
require Math::PlanePath::SierpinskiArrowheadCentres;
require Math::PlanePath::SquareSpiral;
require Math::PlanePath::PentSpiral;
require Math::PlanePath::PentSpiralSkewed;
require Math::PlanePath::HexArms;
require Math::PlanePath::TriangleSpiral;
require Math::PlanePath::TriangleSpiralSkewed;
require Math::PlanePath::KochelCurve;
require Math::PlanePath::MPeaks;
require Math::PlanePath::CincoCurve;
require Math::PlanePath::DiagonalRationals;
require Math::PlanePath::FactorRationals;
require Math::PlanePath::VogelFloret;
require Math::PlanePath::CellularRule;
require Math::PlanePath::ComplexPlus;
require Math::PlanePath::AnvilSpiral;
require Math::PlanePath::CellularRule57;
require Math::PlanePath::CretanLabyrinth;
require Math::PlanePath::PeanoHalf;
require Math::PlanePath::StaircaseAlternating;
require Math::PlanePath::SierpinskiCurveStair;
require Math::PlanePath::AztecDiamondRings;
require Math::PlanePath::PyramidRows;
require Math::PlanePath::MultipleRings;
require Math::PlanePath::SacksSpiral;
require Math::PlanePath::TheodorusSpiral;
require Math::PlanePath::FilledRings;
require Math::PlanePath::ImaginaryHalf;
require Math::PlanePath::MooreSpiral;
require Math::PlanePath::QuintetSide;
require Math::PlanePath::PeanoRounded;
require Math::PlanePath::GosperSide;
$path_class = 'Math::PlanePath::ComplexMinus';
$path_class = 'Math::PlanePath::QuadricCurve';
$path_class = 'Math::PlanePath::QuintetReplicate';
$path_class = 'Math::PlanePath::SierpinskiCurve';
$path_class = 'Math::PlanePath::LTiling';
$path_class = 'Math::PlanePath::ImaginaryHalf';
$path_class = 'Math::PlanePath::ImaginaryBase';
$path_class = 'Math::PlanePath::TerdragonCurve';
$path_class = 'Math::PlanePath::TerdragonMidpoint';
$path_class = 'Math::PlanePath::TerdragonRounded';
$path_class = 'Math::PlanePath::DragonCurve';
$path_class = 'Math::PlanePath::SierpinskiArrowhead';
$path_class = 'Math::PlanePath::DragonMidpoint';
$path_class = 'Math::PlanePath::QuintetCentres';
$path_class = 'Math::PlanePath::QuintetCurve';
$path_class = 'Math::PlanePath::GosperReplicate';
$path_class = 'Math::PlanePath::HIndexing';
$path_class = 'Math::PlanePath::CornerReplicate';
$path_class = 'Math::PlanePath::WunderlichMeander';
$path_class = 'Math::PlanePath::ComplexRevolving';
$path_class = 'Math::PlanePath::AlternatePaper';
$path_class = 'Math::PlanePath::WunderlichSerpentine';
$path_class = 'Math::PlanePath::PeanoCurve';
$path_class = 'Math::PlanePath::Flowsnake';
$path_class = 'Math::PlanePath::FlowsnakeCentres';
$path_class = 'Math::PlanePath::FractionsTree';
$path_class = 'Math::PlanePath::RationalsTree';
$path_class = 'Math::PlanePath::GrayCode';
$path_class = 'Math::PlanePath::CubicBase';
$path_class = 'Math::PlanePath::R5DragonCurve';
$path_class = 'Math::PlanePath::R5DragonMidpoint';
$path_class = 'Math::PlanePath::HilbertSpiral';
$path_class = 'Math::PlanePath::BetaOmega';
$path_class = 'Math::PlanePath::AR2W2Curve';
$path_class = 'Math::PlanePath::CCurve';
$path_class = 'Math::PlanePath::GcdRationals';
$path_class = 'Math::PlanePath::DiagonalsOctant';
$path_class = 'Math::PlanePath::KochSnowflakes';
$path_class = 'Math::PlanePath::GosperIslands';
$path_class = 'Math::PlanePath::Corner';
$path_class = 'Math::PlanePath::KochCurve';
$path_class = 'Math::PlanePath::QuadricIslands';
$path_class = 'Math::PlanePath::KochPeaks';
$path_class = 'Math::PlanePath::UlamWarburton';
$path_class = 'Math::PlanePath::DragonRounded';
Module::Load::load($path_class);
my $path = $path_class->new
(
);
### $path
my ($prev_x, $prev_y);
my %seen;
my $n_start = $path->n_start;
my $arms_count = $path->arms_count;
print "n_start $n_start arms_count $arms_count ",ref($path),"\n";
for (my $i = $n_start+0; $i <= 32; $i+=1) {
#for (my $i = $n_start; $i <= $n_start + 800000; $i=POSIX::ceil($i*2.01+1)) {
my @n_children = $path->MathImage__tree_n_children($i);
my $n_children = join(', ', @n_children);
my $iwidth = ($i == int($i) ? 0 : 2);
printf "%.*f %s\n",
$iwidth,$i,
$n_children;
foreach my $n_child (@n_children) {
my $n_parent = $path->MathImage__tree_n_parent($n_child);
if (! defined $n_parent || $n_parent != $i) {
$n_parent //= 'undef';
print " oops child=$n_child, parent=$n_parent\n";
}
}
}
exit 0;
}
Math-PlanePath-113/devel/multiple-rings.pl 0000644 0001750 0001750 00000034536 12236026672 016327 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::Libm 'hypot';
use Math::Trig 'pi','tan';
use Math::PlanePath::MultipleRings;
# uncomment this to run the ### lines
use Smart::Comments;
{
require Math::NumSeq::PlanePathDelta;
foreach my $step (3 .. 10) {
print "$step\n";
my $path = Math::PlanePath::MultipleRings->new (step => $step,
ring_shape => 'polygon');
foreach my $n (0 .. $step-1) {
my ($dx,$dy) = $path->n_to_dxdy($n+$path->n_start);
my $dir4 = Math::NumSeq::PlanePathDelta::_delta_func_Dir4($dx,$dy);
printf "%2d %6.3f,%6.3f %6.3f\n", $n, $dx,$dy, $dir4;
}
# my $m = int((3*$step-3)/4);
# $m = int((2*$step-4)/4);
my $m = 2*$step - 2 + ($step%2);
my ($cx,$cy) = Math::PlanePath::MultipleRings::_circlefrac_to_xy
(1, $m, 2*$step, pi());
# $cx = -$cx;
my $dir4 = Math::NumSeq::PlanePathDelta::_delta_func_Dir4($cx,$cy);
print "$m $cx, $cy $dir4\n";
print "\n";
}
exit 0;
}
{
foreach my $step (0 .. 10) {
my $path = Math::PlanePath::MultipleRings->new (step => $step,
ring_shape => 'polygon');
for (my $n = $path->n_start; $n < 10; $n++) {
my ($x, $y) = $path->n_to_xy($n);
my $g = gcd($x,$y);
printf "%2d %6.3f,%6.3f %.8g\n", $n, $x,$y, $g;
}
print "\n";
}
use POSIX 'fmod';
sub gcd {
my ($x,$y) = @_;
$x = abs($x);
$y = abs($y);
unless ($x > 0) {
return $y;
}
# if (is_infinite($x)) { return $x; }
# if (is_infinite($y)) { return $y; }
if ($y > $x) {
$y = fmod($y,$x);
}
for (;;) {
### gcd at: "x=$x y=$y"
if ($y == 0) {
return $x; # gcd(x,0)=x
}
if ($y < 0.0001) {
return 0.00001;
}
($x,$y) = ($y, fmod($x,$y));
}
}
exit 0;
}
{
require Math::BigFloat;
# Math::BigFloat->precision(-3);
my $n = Math::BigFloat->new(4);
# $n->accuracy(5);
$n->precision(-3);
my $pi = Math::PlanePath::MultipleRings::_pi($n);
print "$pi\n";
exit 0;
}
{
my $pi = pi();
my $offset = 0.0;
foreach my $step (3,4,5,6,7,8) {
my $path = Math::PlanePath::MultipleRings->new (step => $step,
ring_shape => 'polygon');
my $d = 1;
my $n0base = Math::PlanePath::MultipleRings::_d_to_n0base($path,$d);
my $next_n0base = Math::PlanePath::MultipleRings::_d_to_n0base($path,$d+10);
my ($pbase, $pinc);
if ($step > 6) {
$pbase = 0;
$pinc = Math::PlanePath::MultipleRings::_numsides_to_r($step,$pi);
} else {
$pbase = Math::PlanePath::MultipleRings::_numsides_to_r($step,$pi);
$pinc = 1/cos($pi/$step);
}
print "step=$step pbase=$pbase pinc=$pinc\n";
for (my $n = $n0base+$path->n_start; $n < $next_n0base; $n += 1.0) {
my ($x, $y) = $path->n_to_xy($n);
my $revn = $path->xy_to_n($x-$offset,$y) // 'undef';
my $r = hypot ($x, $y);
my $theta_frac = Math::PlanePath::MultipleRings::_xy_to_angle_frac($x,$y);
$theta_frac -= int($theta_frac*$step) / $step; # modulo 1/step
my $alpha = 2*$pi/$step;
my $theta = 2*$pi * $theta_frac;
### $r
### x=r*cos(theta): $r*cos($theta)
### y=r*sin(theta): $r*sin($theta)
my $p = $r*cos($theta) + $r*sin($theta) * sin($alpha/2)/cos($alpha/2);
$d = ($p - $pbase) / $pinc + 1;
printf "%5.1f thetafrac=%.4f r=%.4f p=%.4f d=%.2f revn=%s\n",
$n, $theta_frac, $r, $p, $d, $revn;
if ($n==int($n) && (! defined $revn || $revn != $n)) {
print "\n";
die "oops, revn=$revn != n=$n";
}
}
print "\n";
}
exit 0;
}
{
# dir_minimum_dxdy() position
require Math::PlanePath::MultipleRings;
require Math::NumSeq::PlanePathDelta;
foreach my $step (3 .. 100) {
my $path = Math::PlanePath::MultipleRings->new (step => $step,
ring_shape => 'polygon');
my $min_dir4 = 99;
my $min_n = 1;
my $max_dir4 = 0;
my $max_n = 1;
foreach my $n (1 .. $step) {
my ($dx,$dy) = $path->n_to_dxdy($n);
my $dir4 = Math::NumSeq::PlanePathDelta::_delta_func_Dir4($dx,$dy);
if ($dir4 > $max_dir4) {
$max_dir4 = $dir4;
$max_n = $n;
}
if ($dir4 < $min_dir4) {
$min_dir4 = $dir4;
$min_n = $n;
}
}
my $min_diff = $step - $min_n;
my $max_diff = $step - $max_n;
print "$step min N=$min_n $min_diff max N=$max_n $max_diff\n";
}
exit 0;
}
{
# Dir4 minimum, maximum
require Math::PlanePath::MultipleRings;
foreach my $step (3 .. 20) {
my $path = Math::PlanePath::MultipleRings->new (step => $step,
ring_shape => 'polygon');
my $min = $path->dir4_minimum();
my $max = $path->dir4_maximum();
my $den = 2*$step;
$min *= $den;
$max *= $den;
my $md = 4*$den - $max;
print "$step $min $max($md) / $den\n";
}
exit 0;
}
{
# polygon pack
my $poly = 5;
# w/c = tan(angle/2)
# w = c*tan(angle/2)
# (c/row)^2 + (c-prev)^2 = 1
# 1/row^2 * c^2 + (c^2 - 2cp + p^2) = 1
# 1/row^2 * c^2 + c^2 - 2cp + p^2 - 1 = 0
# (1/row^2 + 1) * c^2 - 2p*c + (p^2 - 1) = 0
# A = (1 + 1/row^2)
# B = -2p
# C = (p^2-1)
# c = (2p + sqrt(4p^2 - 4*(p^2+1)*(1 + 1/row^2))) / (2*(1 + 1/row^2))
# d = c-prev
# c = d+prev
# ((d+prev)/row)^2 + d^2 = 1
# (d^2+2dp+p^2)/row^2 + d^2 = 1
# d^2/row^2 + 2p/row^2 * d + p^2/row^2 + d^2 - 1 = 0
# (1+1/row^2)*d^2 + 2p/row^2 * d + (p^2/row^2 - 1) = 0
# A = (1+1/row^2)
# B = 2p/row^2
# C = (p^2/row^2 - 1)
my $angle_frac = 1/$poly;
my $angle_degrees = $angle_frac * 360;
my $angle_radians = 2*pi * $angle_frac;
my $slope = 1/cos($angle_radians/2); # e = slope*c
my $tan = tan($angle_radians/2);
print "angle $angle_degrees slope $slope tan=$tan\n";
my @c = (0);
my @e = (0);
my @points_on_row;
my $delta_minimum = 1/$slope;
my $delta_minimum_hypot = hypot($delta_minimum, $delta_minimum*$tan);
print "delta_minimum = $delta_minimum (hypot $delta_minimum_hypot)\n";
# tan a/2 = 0.5/c
# c = 0.5 / tan(a/2)
my $c = 0.5 / tan($angle_radians/2);
my $e = $c * $slope;
$c[1] = $c;
$e[1] = $e;
my $w = $c*$tan;
print "row=1 initial c=$c e=$e w=$w\n";
{
my $delta_equil = sqrt(3)/2;
my $delta_side = cos($angle_radians/2);
print " delta equil=$delta_equil side=$delta_side\n";
if ($delta_equil > $delta_side) {
$c += $delta_equil;
$w = $c*$tan;
print "row=2 equilateral to c=$c w=$w\n";
} else {
$c += $delta_side;
$w = $c*$tan;
print "row=2 side to c=$c w=$w\n";
}
}
$e = $c * $slope;
$c[2] = $c;
$e[2] = $e;
# for (my $row = 3; $row < 27; $row += 2) {
# my $p = $c;
#
# # # (p - (row-2)/row * c)^2 + (c-p)^2 = 1
# # # p^2 - 2*rf*p*c + rf^2*c^2 + c^2 - 2cp + p^2 - 1 = 0
# # # rf^2*c^2 + c^2 - 2*rf*p*c - 2*p*c + p^2 + p^2 - 1 = 0
# # # (rf^2 + 1)*c^2 + (- 2*rf*p - 2*p)*c + (p^2 + p^2 - 1) = 0
# # # (rf^2 + 1)*c^2 + -2*p*(rf+1)*c + (p^2 + p^2 - 1) = 0
# # #
# # my $rf = ($row-2)/$row;
# # my $A = ($rf^2 + 1);
# # my $B = -2*$rf*$p - 2*$p;
# # my $C = (2*$p**2 - 1);
# # print "A=$A B=$B C=$C\n";
# # my $next_c;
# # my $delta;
# # if ($B*$B - 4*$A*$C >= 0) {
# # $next_c = (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
# # $delta = $next_c - $c;
# # } else {
# # $delta = .7;
# # $next_c = $c + $delta;
# #
# # my $side = ($c - $rf*$next_c);
# # my $h = hypot($side, $delta);
# # print " h=$h\n";
# # }
#
# # delta of i=0 j=1
# #
# # (p - (row-2)/row * c)^2 + d^2 = 1
# # (p - rf*(p+d))^2 + d^2 = 1
# # (p - rf*p - rf*d))^2 + d^2 = 1
# # (-p + rf*p + rf*d))^2 + d^2 = 1
# # (rf*d -p + rf*p)^2 + d^2 = 1
# # (rf*d + (rf-1)p)^2 + d^2 = 1
# # rf^2*d^2 + 2*rf*(rf-1)*p * d + (rf-1)^2*p^2 + d^2 - 1 = 0
# # (rf^2+1)*d^2 + rf*(rf-1)*p * d + ((rf-1)^2*p^2 - 1) = 0
# #
# my $rf = ($row-2)/$row;
# $rf = ($row+1 -2)/($row+1);
# my $A = $rf**2 + 1;
# my $B = 2*$rf*($rf-1)*$p;
# my $C = ($rf-1)**2 * $p**2 - 1;
# my $delta;
# if ($B*$B - 4*$A*$C >= 0) {
# $delta = (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
# } else {
# print "discrim: ",$B*$B - 4*$A*$C,"\n";
# $delta = 0;
# }
#
# # delta of i=0 j=0
# # (c - p)^2 + d^2 = 1
# #
# if ($delta < $delta_minimum+.0) {
# print " side minimum $delta < $delta_minimum\n";
# $delta = $delta_minimum;
# }
# my $next_c = $delta + $c;
#
#
# # my $A = (1 + ($tan/$row)**2);
# # my $B = -2*$c;
# # my $C = ($c**2 - 1);
# # my $next_c = (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
# # my $delta = $next_c - $c;
# #
# # $A = (1 + ($tan/$row)**2);
# # $B = 2*$c/$row**2;
# # $C = ($c**2/$row**2 - 1);
# # my $delta_2 = 0; # (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
# # printf "row=$row delta=%.5f=%.5f next_c=%.5f\n", $delta, $delta_2, $next_c;
# printf "row=$row delta=%.5f next_c=%.5f\n", $delta, $next_c;
#
# $c[$row] = $c + $delta;
# $c[$row+1] = $c + 2*$delta;
#
# $e[$row] = $c[$row] * $slope;
# $e[$row+1] = $c[$row+1] * $slope;
#
# $c += 2*$delta;
# }
for (my $row = 3; $row < 138; $row++) {
my $p = $c;
# # (p - (row-2)/row * c)^2 + (c-p)^2 = 1
# # p^2 - 2*rf*p*c + rf^2*c^2 + c^2 - 2cp + p^2 - 1 = 0
# # rf^2*c^2 + c^2 - 2*rf*p*c - 2*p*c + p^2 + p^2 - 1 = 0
# # (rf^2 + 1)*c^2 + (- 2*rf*p - 2*p)*c + (p^2 + p^2 - 1) = 0
# # (rf^2 + 1)*c^2 + -2*p*(rf+1)*c + (p^2 + p^2 - 1) = 0
# #
# my $rf = ($row-2)/$row;
# my $A = ($rf^2 + 1);
# my $B = -2*$rf*$p - 2*$p;
# my $C = (2*$p**2 - 1);
# print "A=$A B=$B C=$C\n";
# my $next_c;
# my $delta;
# if ($B*$B - 4*$A*$C >= 0) {
# $next_c = (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
# $delta = $next_c - $c;
# } else {
# $delta = .7;
# $next_c = $c + $delta;
#
# my $side = ($c - $rf*$next_c);
# my $h = hypot($side, $delta);
# print " h=$h\n";
# }
# delta of i=0 j=1
#
# (p*tan - (row-2)/row * tan*c)^2 + d^2 = 1
# tt*(p - rf*(p+d))^2 + d^2 = 1
# tt*(p - rf*p - rf*d)^2 + d^2 = 1
# tt*(-p + rf*p + rf*d)^2 + d^2-1 = 0
# tt*(rf*d -p + rf*p)^2 + d^2-1 = 0
# tt*(rf*d + (rf-1)p)^2 + d^2-1 = 0
# tt*rf^2*d^2 + tt*2*rf*(rf-1)*p * d + tt*(rf-1)^2*p^2 + d^2 - 1 = 0
# (tt*rf^2+1)*d^2 + tt*rf*(rf-1)*p * d + (tt*(rf-1)^2*p^2 - 1) = 0
#
# print " rf ",($row-2),"/$row\n";
my $rf = ($row-2)/($row);
my $A = $tan**2 * $rf**2 + 1;
my $B = $tan**2 * 2*$rf*($rf-1)*$p;
my $C = $tan**2 * ($rf-1)**2 * $p**2 - 1;
my $delta;
if ($B*$B - 4*$A*$C >= 0) {
$delta = (-$B + sqrt($B*$B - 4*$A*$C))/(2*$A);
my $next_c = $delta + $c;
my $pw = $p * $tan;
my $next_w = $next_c * $tan;
my $rem = $pw - $next_w*($row-2)/$row;
my $h = hypot ($delta, $rem);
# print " h^2=$h pw=$pw nw=$next_w rem=$rem\n";
} else {
print "discrim: ",$B*$B - 4*$A*$C,"\n";
my $w = $p*$tan / $row;
print " at d=0 w=$w\n";
$delta = 0;
}
# delta of i=0 j=0
# (c - p)^2 + d^2 = 1
#
if ($delta < $delta_minimum+.0) {
print " side minimum $delta < $delta_minimum\n";
$delta = $delta_minimum;
}
my $next_c = $delta + $c;
printf "row=$row delta=%.5f next_c=%.5f\n", $delta, $next_c;
$c += $delta;
$c[$row] = $c;
$e[$row] = $c[$row] * $slope;
}
# print "c ",join(', ',@c),"\n";
# print "e ",join(', ',@e),"\n";
my (@x,@y);
foreach my $row (1 .. $#c) {
my $x1 = $e[$row];
my $y1 = 0;
my ($x2,$y2) = Math::Trig::cylindrical_to_cartesian($e[$row],
$angle_radians, 0);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
foreach my $p (0 .. $row) {
$x[$row][$p] = $x1 + $dx*$p/$row;
$y[$row][$p] = $y1 + $dy*$p/$row;
}
# print "row=$row x ",join(', ',@{$x[$row]}),"\n";
}
foreach my $row (1 .. $#c-1) {
print "\n";
my $min_dist = 9999;
my $min_dist_at_i = -1;
my $min_dist_at_j = -1;
foreach my $i (0 .. $row) {
foreach my $j (0 .. $row+1) {
my $dist = hypot($x[$row][$i] - $x[$row+1][$j],
$y[$row][$i] - $y[$row+1][$j]);
if ($dist < $min_dist) {
# print " dist=$dist at i=$i j=$j\n";
$min_dist = $dist;
$min_dist_at_i = $i;
$min_dist_at_j = $j;
}
}
}
if ($min_dist_at_i > $row/2) {
$min_dist_at_i = $row - $min_dist_at_i;
$min_dist_at_j = $row+1 - $min_dist_at_j;
}
print "row=$row min_dist=$min_dist at i=$min_dist_at_i j=$min_dist_at_j\n";
my $zdist = hypot($x[$row][0] - $x[$row+1][0],
$y[$row][0] - $y[$row+1][0]);
my $odist = hypot($x[$row][0] - $x[$row+1][1],
$y[$row][0] - $y[$row+1][1]);
print " zdist=$zdist odist=$odist\n";
}
open OUT, '>', '/tmp/multiple-rings.tmp' or die;
foreach my $row (1 .. $#c-1) {
foreach my $i (0 .. $row) {
print OUT "$x[$row][$i], $y[$row][$i]\n";
}
}
close OUT or die;
system ('math-image --wx --path=File,filename=/tmp/multiple-rings.tmp --all --scale=25 --figure=ring');
exit 0;
}
{
# max dx
require Math::PlanePath::MultipleRings;
my $path = Math::PlanePath::MultipleRings->new (step => 37);
my $n = $path->n_start;
my $dx_max = 0;
my ($prev_x, $prev_y) = $path->n_to_xy($n++);
foreach (1 .. 1000000) {
my ($x, $y) = $path->n_to_xy($n++);
my $dx = $y - $prev_y;
if ($dx > $dx_max) {
print "$n $dx\n";
$dx_max = $dx;
}
$prev_x = $x;
$prev_y = $y;
}
exit 0;
}
Math-PlanePath-113/devel/gray.pl 0000644 0001750 0001750 00000017673 12070210366 014310 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::Prime::XS 0.23 'is_prime'; # version 0.23 fix for 1928099
use Math::PlanePath::GrayCode;
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
# uncomment this to run the ### lines
use Smart::Comments;
{
# turn Left
# 1,1,0,0,1,1,1,
# left at N=1,2 then 180 at N=3
# 7to8
# N=2,3,4 same Y
# parity of A065883
require Math::NumSeq::PlanePathTurn;
my $planepath;
$planepath = "GrayCode";
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => $planepath,
turn_type => 'LSR');
my $path = $seq->{'planepath_object'};
for (1 .. 60) {
my ($n, $turn) = $seq->next;
# next if $value;
my ($x,$y) = $path->n_to_xy($n);
my ($dx,$dy) = $path->n_to_dxdy($n);
my $calc = calc_left_turn($n);
print "$n $x,$y $turn $calc dxdy=$dx,$dy\n";
# printf "%d,", $value;
# printf " i-1 gray %6b\n",to_gray($n-1,2);
# printf " i gray %6b\n",to_gray($n,2);
# printf " i+1 gray %6b\n",to_gray($n+1,2);
}
print "\n";
exit 0;
sub calc_left_turn {
my ($n) = @_;
return count_low_0_bits(($n+1)>>1) % 2 ? 0 : 1;
}
sub count_low_1_bits {
my ($n) = @_;
my $count = 0;
while ($n % 2) {
$count++;
$n = int($n/2);
}
return $count;
}
sub count_low_0_bits {
my ($n) = @_;
if ($n == 0) { die; }
my $count = 0;
until ($n % 2) {
$count++;
$n /= 2;
}
return $count;
}
}
{
# cf GRS
require Math::NumSeq::GolayRudinShapiro;
require Math::NumSeq::DigitCount;
my $seq = Math::NumSeq::GolayRudinShapiro->new;
my $dc = Math::NumSeq::DigitCount->new (radix => 2);
for (my $n = 0; $n < 2000; $n++) {
my $grs = $seq->ith($n);
my $gray = from_binary_gray($n);
my $gbit = $dc->ith($gray) & 1;
printf "%3d %2d %2d\n", $n, $grs, $gbit;
}
exit 0;
}
{
# X,Y,Diagonal values
foreach my $apply_type ('TsF','Ts','sT','sF') {
print "$apply_type\n";
my $path = Math::PlanePath::GrayCode->new (apply_type => $apply_type);
foreach my $i (0 .. 40) {
my $nx = $path->xy_to_n(0,$i);
printf "%d %d %b\n", $i, $nx, $nx;
}
}
exit 0;
}
{
# path sameness
require Tie::IxHash;
my @apply_types = ('TsF','Ts','Fs','FsT','sT','sF');
my @gray_types = ('reflected',
'modular',
);
for (my $radix = 2; $radix <= 10; $radix++) {
print "radix $radix\n";
my %xy;
tie %xy, 'Tie::IxHash';
foreach my $apply_type (@apply_types) {
foreach my $gray_type (@gray_types) {
my $path = Math::PlanePath::GrayCode->new
(radix => $radix,
apply_type => $apply_type,
gray_type => $gray_type);
my $str = '';
foreach my $n (0 .. $radix ** 4) {
my ($x,$y) = $path->n_to_xy($n);
$str .= " $x,$y";
}
push @{$xy{$str}}, "$apply_type,$gray_type";
}
}
my @distinct;
foreach my $aref (values %xy) {
if (@$aref > 1) {
print " same: ",join(' ',@$aref),"\n";
} else {
push @distinct, @$aref;
}
}
print " distinct: ",join(' ',@distinct),"\n";
}
exit 0;
}
{
# to_gray() same as from_gray() in some radices
for (my $radix = 2; $radix < 20; $radix++) {
my $result = "same";
for (my $n = 0; $n < 2000; $n++) {
my $to = to_gray($n,$radix);
my $from = from_gray($n,$radix);
if ($to != $from) {
$result = "different";
last;
}
}
print "radix=$radix to/from $result\n";
}
exit 0;
sub to_gray {
my ($n, $radix) = @_;
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,$radix);
return digit_join_lowtohigh($digits,$radix);
}
sub from_gray {
my ($n, $radix) = @_;
my $digits = [ digit_split_lowtohigh($n,$radix) ];
Math::PlanePath::GrayCode::_digits_from_gray_reflected($digits,$radix);
return digit_join_lowtohigh($digits,$radix);
}
}
{
for (my $n = 0; $n < 2000; $n++) {
next unless is_prime($n);
my $gray = to_binary_gray($n);
next unless is_prime($gray);
printf "%3d %3d\n", $n, $gray;
}
exit 0;
sub to_binary_gray {
my ($n) = @_;
my $digits = [ digit_split_lowtohigh($n,2) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,2);
return digit_join_lowtohigh($digits,2);
}
}
{
require Math::BaseCnv;
my $radix = 10;
my $num = 3;
my $width = length($radix)*2*$num;
foreach my $i (0 .. $radix ** $num - 1) {
my $i_digits = [ digit_split_lowtohigh($i,$radix) ];
my @gray_digits = @$i_digits;
my $gray_digits = \@gray_digits;
Math::PlanePath::GrayCode::_digits_to_gray_reflected($gray_digits,$radix);
# Math::PlanePath::GrayCode::_digits_to_gray_modular($gray_digits,$radix);
my @rev_digits = @gray_digits;
my $rev_digits = \@rev_digits;
Math::PlanePath::GrayCode::_digits_from_gray_reflected($rev_digits,$radix);
# Math::PlanePath::GrayCode::_digits_from_gray_modular($rev_digits,$radix);
my $i_str = join(',', reverse @$i_digits);
my $gray_str = join(',', reverse @$gray_digits);
my $rev_str = join(',', reverse @$rev_digits);
my $diff = ($i_str eq $rev_str ? '' : ' ***');
printf "%*s %*s %*s%s\n",
$width,$i_str, $width,$gray_str, $width,$rev_str,
$diff;
}
exit 0;
}
{
foreach my $i (0 .. 32) {
printf "%05b %05b\n", $i, from_binary_gray($i);
}
sub from_binary_gray {
my ($n) = @_;
my @digits;
while ($n) {
push @digits, $n & 1;
$n >>= 1;
}
my $xor = 0;
my $ret = 0;
while (@digits) {
my $digit = pop @digits;
$ret <<= 1;
$ret |= $digit^$xor;
$xor ^= $digit;
}
return $ret;
}
exit 0;
}
# integer modular
# 000 000
# 001 001
# 002 002
# 010 012
# 011 010
# 012 011
# 020 021
# 021 022
# 022 020
# integer reflected
# 000 000
# 001 001
# 002 002
# 010 012
# 011 011
# 012 010
# 020 020
# 021 021
# 022 022
# 100 122
# 101 121
# 102 120
# 110 110
# 111 111
# 112 112
# 120 102
# 121 101
# 122 100
#
# 200 200
# A128173 ternary reverse
# 0, 000
# 1, 001
# 2, 002
# 5, 012
# 4, 011
# 3, 010
# 6, 020
# 7, 021
# 8, 022
# 17, 122
# 16, 121
# 15, 120
# 12, 110
# 13, 111
# 14, 112
# 11, 102
# 10, 101
# 9, 100
# 18, 200
# A105530 ternary cyclic
# 0, 000
# 1, 001
# 2, 002
# 5, 012
# 3, 010
# 4, 011
# 7, 021
# 8, 022
# 6, 020
# 15, 120
# 16, 121
# 17, 122
# 11, 102
# 9, 100
# 10, 101
# 13, 111
# 14, 112
# 12, 110
# 21, 210
# 22, 211
#
sub _to_gray {
my ($n) = @_;
### _to_gray(): $n
return ($n >> 1) ^ $n;
}
sub _from_gray {
my ($n) = @_;
### _from_gray(): $n
my $shift = 1;
for (;;) {
my $xor = ($n >> $shift) || return $n;
$n ^= $xor;
$shift *= 2;
}
# my @digits;
# while ($n) {
# push @digits, $n & 1;
# $n >>= 1;
# }
# my $xor = 0;
# my $ret = 0;
# while (@digits) {
# my $digit = pop @digits;
# $ret <<= 1;
# $ret |= $digit^$xor;
# $xor ^= $digit;
# }
# return $ret;
}
Math-PlanePath-113/devel/quadric.pl 0000644 0001750 0001750 00000007613 11753407263 015002 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
{
# QuadricIslands X negative axis N increasing
require Math::PlanePath::QuadricIslands;
my $path = Math::PlanePath::QuadricIslands->new;
my $prev_n = 0;
for (my $x = 0; $x > -1000000000; $x--) {
my $n = $path->xy_to_n($x,0) // next;
if ($n < $prev_n) {
print "decrease N at X=$x N=$n prev_N=$prev_n\n";
}
$prev_n = $n;
}
}
{
# min/max for level
require Math::PlanePath::QuadricIslands;
my $path = Math::PlanePath::QuadricIslands->new;
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 25; $level++) {
my $n_start = (4*8**$level + 3)/7;
my $n_end = (4*8**($level+1) + 3)/7 - 1;
$n_end = $n_start + 8**$level;
my $min_width = $n_start ** 2;
my $min_pos = '';
my $max_width = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
#my $w = -$y-$x/2;
my $w = abs($y);
if ($w > $max_width) {
$max_width = $w;
$max_pos = "$x,$y n=$n (oct ".sprintf('%o',$n).")";
}
if ($w < $min_width) {
$min_width = $w;
$min_pos = "$x,$y n=$n (oct ".sprintf('%o',$n).")";
}
}
{
my $factor = $max_width / $prev_max;
print " max width $max_width oct ".sprintf('%o',$max_width)." at $max_pos factor $factor\n";
}
{
my $factor = $min_width / ($prev_min||1);
print " min width $min_width oct ".sprintf('%o',$min_width)." at $min_pos factor $factor\n";
}
{
my $formula = (2*4**($level-1) + 1) / 3;
print " cf min formula $formula\n";
}
{
my $formula = (10*4**($level-1) - 1) / 3;
print " cf max formula $formula\n";
}
$prev_max = $max_width;
$prev_min = $min_width;
}
exit 0;
}
{
# min/max for level
require Math::PlanePath::QuadricCurve;
my $path = Math::PlanePath::QuadricCurve->new;
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 25; $level++) {
my $n_start = 8**($level-1);
my $n_end = 8**$level;
my $max_width = 0;
my $max_pos = '';
my $min_width;
my $min_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
$x -= 4**$level / 2; # for Rings
$y -= 4**$level / 2; # for Rings
my $w = -2*$y-$x;
#my $w = -$y-$x/2;
if ($w > $max_width) {
$max_width = $w;
$max_pos = "$x,$y n=$n (oct ".sprintf('%o',$n).")";
}
if (! defined $min_width || $w < $min_width) {
$min_width = $w;
$min_pos = "$x,$y n=$n (oct ".sprintf('%o',$n).")";
}
}
# print " max $max_width at $max_x,$max_y\n";
my $factor = $max_width / $prev_max;
print " min width $min_width oct ".sprintf('%o',$min_width)." at $min_pos factor $factor\n";
# print " max width $max_width oct ".sprintf('%o',$max_width)." at $max_pos factor $factor\n";
# print " cf formula ",(10*4**($level-1) - 1)/3,"\n";
# print " cf formula ",2* (4**($level-0) - 1)/3,"\n";
print " cf formula ",2*4**($level-1),"\n";
$prev_max = $max_width;
}
exit 0;
}
Math-PlanePath-113/devel/dragon.pl 0000644 0001750 0001750 00000207516 12245551530 014622 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::MoreUtils;
use POSIX 'floor';
use Math::Libm 'M_PI', 'hypot';
use List::Util 'min', 'max';
use Math::PlanePath::DragonCurve;
use Math::PlanePath::Base::Digits
'round_down_pow';
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::KochCurve;
*_digit_join_hightolow = \&Math::PlanePath::KochCurve::_digit_join_hightolow;
use lib 'xt';
# uncomment this to run the ### lines
# use Smart::Comments;
{
# LLRR
my $reverse = sub {
my ($str) = @_;
$str = reverse $str;
$str =~ tr/+-/-+/;
return $str;
};
my $str = 'F';
while (length($str) < 8192) {
$str = $str . '+' . $reverse->($str); # unfold left
$str = $str . '+' . $reverse->($str); # unfold left
$str = $str . '-' . $reverse->($str); # unfold right
$str = $str . '-' . $reverse->($str); # unfold right
}
require Language::Logo;
my $lo = Logo->new(update => 2, port => 8200 + (time % 100));
my $draw;
$lo->command("right 45; backward 200; seth 90");
$lo->command("pendown; hideturtle");
my %char_to_command = (F => 'forward 5',
'+' => 'left 90',
'-' => 'right 90',
);
foreach my $char (split //, $str) {
### $char
$lo->command($char_to_command{$char});
}
$lo->disconnect("Finished...");
exit 0;
exit 0;
}
# {
# [0,1,S 1,1,SW 1,0,W 0,0,- ]);
# [1,1,SW 0,1,S 0,0,- 1,0,W ],
#
# [1,0,W 0,0,- 0,1,S 1,1,SW ],
# my @yx_adj_x = ([0,0,- 1,0,W 1,1,SW 0,1,S ],
# }
{
# visited 0,1
my $path = Math::PlanePath::DragonCurve->new;
foreach my $y (reverse -16 .. 16) {
foreach my $x (-32 .. 32) {
print $path->xy_is_visited($x,$y) ? 1 : 0;
}
print "\n";
}
exit 0;
}
{
foreach my $arms (1 .. 4) {
my $path = Math::PlanePath::DragonCurve->new (arms => $arms);
foreach my $x (-50 .. 50) {
foreach my $y (-50 .. 50) {
my $v = !! $path->xy_is_visited($x,$y);
my $n = defined($path->xy_to_n($x,$y));
$v == $n || die "arms=$arms x=$x,y=$y";
}
}
}
exit 0;
}
{
my @m = ([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]);
foreach my $arms (1 .. 4) {
my $path = Math::PlanePath::DragonCurve->new (arms => $arms);
foreach my $x (-50 .. 50) {
foreach my $y (-50 .. 50) {
next if $x == 0 && $y == 0;
my $xm = $x+$y;
my $ym = $y-$x;
my $a1 = Math::PlanePath::DragonMidpoint::_xy_to_arm($xm,$ym);
my $a2 = Math::PlanePath::DragonMidpoint::_xy_to_arm($xm-1,$ym+1);
$m[$a1]->[$a2] = 1;
}
}
}
foreach my $i (0 .. $#m) {
my $aref = $m[$i];
print "$i ",@$aref,"\n";
}
exit 0;
}
{
require Devel::TimeThis;
require Math::PlanePath::DragonMidpoint;
foreach my $arms (1 .. 4) {
my $path = Math::PlanePath::DragonCurve->new (arms => $arms);
{
my $t = Devel::TimeThis->new("xy_is_visited() arms=$arms");
foreach my $x (0 .. 50) {
foreach my $y (0 .. 50) {
$path->xy_is_visited($x,$y);
}
}
}
{
my $t = Devel::TimeThis->new("xy_to_n() arms=$arms");
foreach my $x (0 .. 50) {
foreach my $y (0 .. 50) {
$path->xy_to_n($x,$y);
}
}
}
}
exit 0;
}
{
# Dir4 is count_runs_1bits()
require Math::NumSeq::PlanePathDelta;
my $path = Math::PlanePath::DragonCurve->new;
my $dir4_seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'Dir4');
foreach my $n (0 .. 64) {
my $d = $dir4_seq->ith($n);
my $c = count_runs_1bits($n*2+1) % 4;
printf "%2d %d %d\n", $n, $d, $c;
}
my $n = 0b1100111101;
print join(',',$path->n_to_dxdy($n)),"\n";
exit 0;
}
{
# drawing two towards centre segment order
my @values;
print "\n";
my $draw;
$draw = sub {
my ($from, $to) = @_;
my $mid = ($from + $to) / 2;
if ($mid != int($mid)) {
push @values, min($from,$to);
} else {
$draw->($from,$mid);
$draw->($to,$mid);
}
};
$draw->(0, 64);
print join(',',@values),"\n";
my %seen;
foreach my $value (@values) {
if ($seen{$value}++) {
print "duplicate $value\n";
}
}
require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
foreach my $i (0 .. $#values) {
printf "%2d %7b\n", $i, $values[$i];
}
exit 0;
}
{
# drawing two towards centre with Language::Logo
require Language::Logo;
require Math::NumSeq::PlanePathTurn;
my $lo = Logo->new(update => 20, port => 8200 + (time % 100));
my $draw;
$lo->command("backward 130; hideturtle");
$draw = sub {
my ($level, $length) = @_;
if (--$level < 0) {
$lo->command("pendown; forward $length; penup; backward $length");
return;
}
my $sidelen = $length / sqrt(2);
$lo->command("right 45");
$draw->($level,$sidelen);
$lo->command("left 45");
$lo->command("penup; forward $length");
$lo->command("right 135");
$draw->($level,$sidelen);
$lo->command("left 135");
$lo->command("penup; backward $length");
};
$draw->(8, 300);
$lo->disconnect("Finished...");
exit 0;
}
{
# count repeated points
# diff 4-term feedback 1/(1-2x)(1-x-2x^3)
# = 4*x^4 - 2*x^3 + 2*x^2 - 3*x + 1
# total 1/((1-x)*(1-2x)*(1-x-2x^3)).
# A003476 diff of unrepeated a(n) = a(n-1) + 2a(n-3).
# A003479 overlap points by next 2^n section, x^4
# position of first/last across 2^k
# A155803 A023001 interleaved with 2*A023001 and 4*A023001.
# A023001 (8^n - 1)/7.
# ternary 100100100
$|=1;
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $count = 0;
my $prev = 0;
my $prev_diff = 0;
my $last_pos = 0;
foreach my $n (0 .. 2**20) {
if (is_pow2($n)) {
my $diff = $count - $prev;
my $diff_diff = $diff - $prev_diff;
# printf "%d count=%d[%b] diff=%d[%b] dd=%d\n",
# $n, $count,$count, $diff,$diff, $diff_diff;
# print "$n $count $diff\n";
# print "$count,";
# print "$diff,";
# print "$last_pos,";
$prev = $count;
$prev_diff = $diff;
$last_pos = 0;
}
my ($x, $y) = $path->n_to_xy ($n);
my @n_list = $path->xy_to_n_list($x,$y);
$count += (@n_list == 2 && $n_list[1] >= next_pow2($n));
if (@n_list == 2 && $n_list[1] >= next_pow2($n)) {
$last_pos = next_pow2($n) - $n;
print "$n_list[0] $n_list[1] at $n last=$last_pos\n";
}
}
exit 0;
sub is_pow2 {
my ($n) = @_;
while ($n > 1) {
if ($n & 1) {
return 0;
}
$n >>= 1;
}
return ($n == 1);
}
sub next_pow2 {
my ($n) = @_;
return 2*high_bit($n);
}
}
{
# (i-1)^k
use lib 'xt';
require MyOEIS;
require Math::Complex;
my $b = Math::Complex->make(-1,1);
my $c = Math::Complex->make(1);
my @values;
foreach (0 .. 16) {
push @values, $c->Re;
$c *= $b;
}
print join(',',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
print "\n";
exit 0;
}
{
# unrepeated points
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
foreach my $n (0 .. 256) {
my ($x, $y) = $path->n_to_xy ($n);
my @n_list = $path->xy_to_n_list($x,$y);
next unless @n_list == 1;
printf "%9b\n", $n;
#print "$n,";
}
exit 0;
}
{
# repeat points
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my %seen;
my %first;
foreach my $n (0 .. 2**10 - 1) {
my ($x, $y) = $path->n_to_xy ($n);
my @n_list = $path->xy_to_n_list($x,$y);
next unless $n_list[0] == $n;
next unless @n_list >= 2;
my $dn = abs($n_list[0] - $n_list[1]);
++$seen{$dn};
$first{$dn} ||= "$x,$y";
}
foreach my $dn (sort {$a<=>$b} keys %seen) {
my $dn2 = sprintf '%b', $dn;
print "dN=${dn}[$dn2] first at $first{$dn} count $seen{$dn}\n";
}
my @seen = sort {$a<=>$b} keys %seen;
print join(',',@seen),"\n";
foreach (@seen) { $_ /= 4; }
print join(',',@seen),"\n";
exit 0;
}
# {
# # X,Y recurrence n = 2^k + rem
# # X+iY(n) = (i+1)^k + (i+1)^k +
# my $w = 8;
# my $path = Math::PlanePath::DragonCurve->new;
# foreach my $n (0 .. 1000) {
# my ($x,$y) = $path->n_to_xy($n);
#
# }
# exit 0;
#
sub high_bit {
my ($n) = @_;
my $bit = 1;
while ($bit <= $n) {
$bit <<= 1;
}
return $bit >> 1;
}
# }
{
# d(2n) = d(n)*(i+1)
# d(2n+1) = d(2n) + 1-(transitions(2*$n) % 4)
# 2n to 2n+1 is always horizontal
# transitions(2n) is always even since return to 0 at the low end
#
# X(2n-1) \ = X(n)
# X(2n) /
# X(2n+1) \ = X(2n) + (-1) ** count_runs_1bits($n)
# X(2n+2) /
#
# X(2n-1) \ = X(n)
# X(2n) /
# X(2n+1) \ = X(2n) + (-1) ** count_runs_1bits($n)
# X(2n+2) /
# X(n) = cumulative dx = (-1) ** count_runs_1bits(2n)
# Y(n) = cumulative dy = (-1) ** count_runs_1bits(2n+1)
# Dragon delta = bisection of count runs 1s
# Alternate delta = bisection of count even runs 1s
{
require Math::NumSeq::OEIS;
my $seq = Math::NumSeq::OEIS->new(anum=>'A005811'); # num runs
my @array;
sub A005811 {
my ($i) = @_;
while ($#array < $i) {
my ($i,$value) = $seq->next;
$array[$i] = $value;
}
return $array[$i];
}
}
my $path = Math::PlanePath::DragonCurve->new;
foreach my $n (0 .. 32) {
my ($x,$y) = $path->n_to_xy(2*$n+1);
my ($x1,$y1) = $path->n_to_xy(2*$n+2);
my $dx = $x1-$x;
my $dy = $y1-$y;
# my $transitions = transitions(2*$n);
# my $c = 1 - (A005811(2*$n) % 4);
# my $c = 1 - 2*(count_runs_1bits(2*$n) % 2);
# my $c = (count_runs_1bits($n)%2 ? -1 : 1);
# my $c = 2-(transitions(2*$n+1) % 4); # Y
# my $c = (-1) ** count_runs_1bits(2*$n); # X
my $c = - (-1) ** count_runs_1bits(2*$n+1); # Y
printf "%6b %2d,%2d %d\n", $n, $dx,$dy, $c;
}
print "\n";
exit 0;
}
{
# Recurrence high to low.
# d(2^k + rem) = (i+1)^(k+1) - i*d(2^k-rem)
# = (i+1) * (i+1)^k - i*d(2^k-rem)
# = (i+1)^k + i*(i+1)^k - i*d(2^k-rem)
# = (i+1)^k + i*((i+1)^k - d(2^k-rem))
require Math::Complex;
# print mirror_across_k(Math::Complex->make(2,0),3);
# exit 0;
my $path = Math::PlanePath::DragonCurve->new;
foreach my $n (0 .. 32) {
my ($x,$y) = $path->n_to_xy($n);
my $p = Math::Complex->make($x,$y);
my $d = calc_d_by_high($n);
printf "%6b %8s %8s %s\n", $n, $p,$d, $p-$d;
}
print "\n";
exit 0;
sub calc_d_by_high {
my ($n) = @_;
if ($n == 0) { return 0; }
my $k = high_bit_pos($n);
my $pow = 1<<$k;
my $rem = $n - $pow;
### $k
### $rem
if ($rem == 0) {
return i_plus_1_pow($k);
} else {
return i_plus_1_pow($k+1)
+ Math::Complex->make(0,-1) * calc_d_by_high($pow-$rem);
}
}
sub high_bit_pos {
my ($n) = @_;
die "high_bit_pos $n" if $n <= 0;
my $bit = 1;
my $pos = 0;
while ($n > 1) {
$n >>= 1;
$pos++;
}
return $pos;
}
sub i_plus_1_pow {
my ($k) = @_;
my $b = Math::Complex->make(1,1);
my $c = Math::Complex->make(1);
for (1 .. $k) { $c *= $b; }
return $c;
}
# # no, not symmetric lengthwise
# return i_plus_1_pow($k)
# + Math::Complex->make(0,1) * mirror_across_k(calc_d_by_high($rem),
# 4-$k);
sub mirror_across_k {
my ($c,$k) = @_;
$k %= 8;
$c *= i_plus_1_pow(8-$k);
# ### c: "$c"
$c = ~$c; # conjugate
# ### conj: "$c"
$c *= i_plus_1_pow($k);
# ### mult: "$c"
$c /= 16; # i_plus_1_pow(8) == 16
# ### ret: "$c"
return $c;
}
}
{
# total turn = count 0<->1 transitions of N bits
sub count_runs_1bits {
my ($n) = @_;
my $count = 0;
for (;;) {
last unless $n;
while ($n % 2 == 0) { $n/=2; }
$count++;
while ($n % 2 == 1) { $n-=1; $n/=2; }
}
return $count;
}
# return how many places there are where n bits change 0<->1
sub transitions {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += (($n & 3) == 1 || ($n & 3) == 2);
$n >>= 1;
}
return $count
}
sub transitions2 {
my ($n) = @_;
my $m = low_ones_mask($n);
$n ^= $m; # zap to zeros
my $count = ($m!=0);
while ($n) {
### assert: ($n&1)==0
$m = low_zeros_mask($n);
$n |= $m; # fill to ones
$count++;
$m = low_ones_mask($n);
$n ^= $m; # zap to zeros
$count++;
last unless $n;
}
return $count
}
sub transitions3 {
my ($n) = @_;
my $count = 0;
return count_1_bits($n^($n>>1));
}
sub low_zeros_mask {
my ($n) = @_;
die if $n == 0;
return ($n ^ ($n-1)) >> 1;
}
### assert: low_zeros_mask(1)==0
### assert: low_zeros_mask(2)==1
### assert: low_zeros_mask(3)==0
### assert: low_zeros_mask(4)==3
### assert: low_zeros_mask(12)==3
### assert: low_zeros_mask(10)==1
sub low_ones_mask {
my ($n) = @_;
return ($n ^ ($n+1)) >> 1;
}
### assert: low_ones_mask(1)==1
### assert: low_ones_mask(2)==0
### assert: low_ones_mask(3)==3
### assert: low_ones_mask(5)==1
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n&1);
$n >>= 1;
}
return $count;
}
my $path = Math::PlanePath::DragonCurve->new;
require Math::NumSeq::PlanePathDelta;
my $dir4_seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'Dir4');
require Math::NumSeq::PlanePathTurn;
my $turn_seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'LSR');
my $total_turn = 0;
for (my $n = 0; $n < 16; ) {
my $t = transitions($n);
my $t2 = transitions2($n);
my $t3 = transitions3($n);
my $good = ($t == $t2 && $t2 == $t3 && $t == $total_turn
? 'good'
: '');
my $dir4 = $dir4_seq->ith($n);
my ($x,$y) = $path->n_to_xy($n);
my $turn = $turn_seq->ith($n+1);
printf "%2d xy=%2d,%2d d=%d total=%d turn=%+d %d,%d,%d %s\n",
$n,$x,$y, $dir4, $total_turn, $turn, $t,$t2,$t3, $good;
$total_turn += $turn;
$n++;
}
exit 0;
}
{
# X,Y recursion
my $w = 8;
my $path = Math::PlanePath::DragonCurve->new;
foreach my $offset (0 .. $w-1) {
my $n = $path->n_start + $offset;
foreach (1 .. 10) {
my ($x,$y) = $path->n_to_xy($n);
print "$x ";
$n += $w;
}
print "\n";
}
exit 0;
}
{
# Midpoint tiling, text lines
require Math::PlanePath::DragonMidpoint;
require Image::Base::Text;
my $scale = 1;
my $arms = 4;
my $path = Math::PlanePath::DragonMidpoint->new (arms => $arms);
my $width = 64;
my $height = 32;
my $xoffset = $width/2;
my $yoffset = $height/2;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my ($nlo,$nhi) = $path->rect_to_n_range(-$xoffset,-$yoffset,
$xoffset,$yoffset);
$nhi = 16384;
print "nhi $nhi\n";
for (my $n = 0; $n <= $nhi; $n++) {
# next if int($n/$arms) % 2;
next unless int($n/$arms) % 2;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+$arms);
my $colour = ($x1 == $x2 ? '|' : '-');
$x1 *= $scale;
$x2 *= $scale;
$y1 *= $scale;
$y2 *= $scale;
$x1 += $xoffset;
$x2 += $xoffset;
$y1 += $yoffset;
$y2 += $yoffset;
$image->line($x1,$y1,$x2,$y2,$colour);
}
$image->save('/dev/stdout');
exit 0;
}
{
# Midpoint tiling, text grid
require Math::PlanePath::DragonMidpoint;
require Image::Base::Text;
my $scale = 2;
my $arms = 4;
my $path = Math::PlanePath::DragonMidpoint->new (arms => $arms);
my $width = 64;
my $height = 32;
my $xoffset = $width/2 - 9;
my $yoffset = $height/2 - 10;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my ($nlo,$nhi) = $path->rect_to_n_range(-$xoffset,-$yoffset,
$xoffset,$yoffset);
$nhi = 16384;
print "nhi $nhi\n";
for (my $n = 0; $n <= $nhi; $n++) {
# next if int($n/$arms) % 2;
next unless int($n/$arms) % 2;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+$arms);
$y1 = -$y1;
$y2 = -$y2;
my $colour = ($x1 == $x2 ? '|' : '-');
($x1,$x2) = (min($x1,$x2),max($x1,$x2));
($y1,$y2) = (min($y1,$y2),max($y1,$y2));
$x1 *= $scale;
$x2 *= $scale;
$y1 *= $scale;
$y2 *= $scale;
$x1 -= $scale/2;
$x2 += $scale/2;
$y1 -= $scale/2;
$y2 += $scale/2;
$x1 += $xoffset;
$x2 += $xoffset;
$y1 += $yoffset;
$y2 += $yoffset;
### rect: $x1,$y1,$x2,$y2
$image->rectangle($x1,$y1,$x2,$y2,'*');
}
$image->save('/dev/stdout');
exit 0;
}
{
# Midpoint tiling, PNG
require Math::PlanePath::DragonMidpoint;
require Image::Base::Text;
require Image::Base::PNGwriter;
my $scale = 4;
my $arms = 1;
my $path = Math::PlanePath::DragonMidpoint->new (arms => $arms);
# my $width = 78;
# my $height = 48;
# my $xoffset = $width/2;
# my $yoffset = $height/2;
# my $image = Image::Base::Text->new (-width => $width,
# -height => $height);
my $width = 1000;
my $height = 800;
my $xoffset = $width/2;
my $yoffset = $height/2;
my $image = Image::Base::PNGwriter->new (-width => $width,
-height => $height);
my $colour = '#00FF00';
my ($nlo,$nhi) = $path->rect_to_n_range(-$xoffset,-$yoffset,
$xoffset,$yoffset);
$nhi = 16384*2;
print "nhi $nhi\n";
for (my $n = 0; $n <= $nhi; $n++) {
# next if int($n/$arms) % 2;
next unless int($n/$arms) % 2;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+$arms);
$x1 *= $scale;
$y1 *= $scale;
$x2 *= $scale;
$y2 *= $scale;
$x1 += $xoffset;
$x2 += $xoffset;
$y1 += $yoffset;
$y2 += $yoffset;
$image->line($x1,$y1,$x2,$y2,$colour);
}
# $image->save('/dev/stdout');
$image->save('/tmp/x.png');
system('xzgv /tmp/x.png');
exit 0;
}
{
# drawing with Language::Logo
require Language::Logo;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new(planepath=>'DragonCurve',
turn_type => 'Right');
my $lo = Logo->new(update => 20);
$lo->command("pendown");
foreach my $n (0 .. 256) {
my ($i,$value) = $seq->next;
my $turn_angle = ($value ? 90 : -90);
$lo->command("forward 10; right $turn_angle");
}
$lo->disconnect("Finished...");
exit 0;
}
{
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new(planepath=>'DragonCurve',
turn_type => 'Right');
foreach my $n (0 .. 16) {
my $dn = dseq($n);
my $turn = $seq->ith($n) // 'undef';
print "$n $turn $dn\n";
}
exit 0;
# Knuth vol 2 answer to 4.5.3 question 41, page 607
sub dseq {
my ($n) = @_;
for (;;) {
if ($n == 0) {
return 1;
}
if (($n % 2) == 0) {
$n >>= 1;
next;
}
if (($n % 4) == 1) {
return 0; # bit above lowest 1-bit
}
if (($n % 4) == 3) {
return 1; # bit above lowest 1-bit
}
}
}
}
{
# rect range exact
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
my @digit_to_rev = (0,5,0,5,undef,
5,0,5,0);
my @min_digit_to_rot = (-1,1,1,-1,0,
0,1,-1,-1,1);
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### DragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $xmax = int(max(abs($x1),abs($x2)));
my $ymax = int(max(abs($y1),abs($y2)));
my ($level_power, $level_max)
= round_down_pow (($xmax*$xmax + $ymax*$ymax + 1) * 7,
2);
### $level_power
### $level_max
if (is_infinite($level_max)) {
return (0, $level_max);
}
my $zero = $x1 * 0 * $y1 * $x2 * $y2;
my $initial_len = 2**$level_max;
### $initial_len
my ($len, $rot, $x, $y);
my $overlap = sub {
my $extent = ($len == 1 ? 0 : 2*$len);
### overlap consider: "xy=$x,$y extent=$extent"
return ($x + $extent >= $x1
&& $x - $extent <= $x2
&& $y + $extent >= $y1
&& $y - $extent <= $y2);
};
my $find_min = sub {
my ($initial_rev, $extra_rot) = @_;
### find_min() ...
### $initial_rev
### $extra_rot
$rot = $level_max + 1 + $extra_rot;
$len = $initial_len;
if ($initial_rev) {
$rot += 2;
$x = 2*$len * $dir4_to_dx[($rot+2)&3];
$y = 2*$len * $dir4_to_dy[($rot+2)&3];
} else {
$x = $zero;
$y = $zero;
}
my @digits = (-1); # high to low
my $rev = $initial_rev;
for (;;) {
my $digit = ++$digits[-1];
### min at: "digits=".join(',',@digits)." xy=$x,$y len=$len rot=".($rot&3)." rev=$rev"
unless ($initial_rev) {
my $nlo = _digit_join_hightolow ([@digits,(0)x($level_max-$#digits)], 4, $zero);
my ($nx,$ny) = $self->n_to_xy($nlo);
my ($nextx,$nexty) = $self->n_to_xy($nlo + $len*$len);
### nlo: "nlo=$nlo xy=$nx,$ny next xy=$nextx,$nexty"
### assert: $x == $nx
### assert: $y == $ny
# ### assert: $nextx == $nx + ($dir4_to_dx[$rot&3] * $len)
# ### assert: $nexty == $ny + ($dir4_to_dy[$rot&3] * $len)
}
$rot += $min_digit_to_rot[$digit+$rev];
### $digit
### rot increment: $min_digit_to_rot[$digit+$rev]." to $rot"
if ($digit > 3) {
pop @digits;
if (! @digits) {
### not found to level_max ...
if ($x1 <= 0 && $x2 >= 0 && $y1 <= 0 && $y2 >= 0) {
### origin covered: 4**($level_max+1)
return 4**$level_max;
} else {
return;
}
}
$rev = (@digits < 2 ? $initial_rev
: $digits[-2]&1 ? 5 : 0);
### past digit=3, backtrack ...
$len *= 2;
next;
}
if (&$overlap()) {
if ($#digits >= $level_max) {
### yes overlap, found n_lo ...
last;
}
### yes overlap, descend ...
### apply rev: "digit=$digit rev=$rev xor=$digit_to_rev[$digit+$rev]"
push @digits, -1;
$rev = ($digit & 1 ? 5 : 0);
$len /= 2;
# {
# my $state = 0;
# foreach (@digits) { if ($_&1) { $state ^= 5 } }
# ### assert: $rev == $state
# }
} else {
### no overlap, next digit ...
$rot &= 3;
$x += $dir4_to_dx[$rot] * $len;
$y += $dir4_to_dy[$rot] * $len;
}
}
### digits: join(',',@digits)
### found n_lo: _digit_join_hightolow (\@digits, 4, $zero)
return _digit_join_hightolow (\@digits, 4, $zero);
};
my $arms = $self->{'arms'};
my @n_lo;
foreach my $arm (0 .. $arms-1) {
if (defined (my $n = &$find_min(0,$arm))) {
push @n_lo, $n*$arms + $arm;
}
}
if (! @n_lo) {
return (1,0); # rectangle not visited by curve
}
my $n_top = 4 * $level_power * $level_power;
### $n_top
my @n_hi;
foreach my $arm (0 .. $arms-1) {
if (defined (my $n = &$find_min(5,$arm))) {
push @n_hi, ($n_top-$n)*$arms + $arm;
}
}
return (min(@n_lo), max(@n_hi));
}
my $path = Math::PlanePath::DragonCurve->new (arms => 4);
foreach my $n (4 .. 1000) {
my ($x,$y) = $path->n_to_xy($n);
my @n_list = $path->xy_to_n_list($x,$y);
my $want_lo = min(@n_list);
my $want_hi = max(@n_list);
my ($lo,$hi) = rect_to_n_range ($path, $x,$y, $x,$y);
print "n=$n lo=$lo wantlo=$want_lo hi=$hi wanthi=$want_hi\n";
if ($lo != $want_lo) {
die "n=$n lo=$lo wantlo=$want_lo";
}
if ($hi != $want_hi) {
die "n=$n hi=$hi wanthi=$want_hi";
}
}
exit 0;
}
{
# level to ymax, xmin
my $path = Math::PlanePath::DragonCurve->new;
my $target = 4;
my $xmin = 0;
my $ymax = 0;
for (my $n = 0; $n < 2**28; $n++) {
my ($x,$y) = $path->n_to_xy($n);
$xmin = min($x,$xmin);
$ymax = max($y,$ymax);
if ($n == $target) {
printf "%7d %14b %14b\n", $n, -$xmin, $ymax;
$target *= 2;
}
}
exit 0;
}
{
# upwards
# 9----8 5---4
# | | | |
# 10--11,7---6 3---2
# | |
# 16 13---12 0---1
# | |
# 15---14
#
#
#
# 8-----> 4
# | ^
# | |
# 16-----> v |
#
#
#
# 2*(4^2-1)/3 = 10 0b1010
# 4*(4^2-1)/3 = 20 0b10100
#
# (2^3+1)/3
# (2^4-1)/3
# (2^5-2)/3 = 10
# (2^6-4)/3 = 20
# (2^7-2)/3 = 42 = 101010
# (2^8-4)/3 = 84 = 1010100
#
# # new xmax = xmax or ymax
# # new xmin = ymin-4
# # new ymax = ymax or -ymin or 2-xmin
# # new ymin = ymin or -ymax or -xmax
#
# 16
# |
# |
# v
# xmin seg 2 <---8
# |
# |
# v
# --->4 xmax seg0
#
# ymin seg 0
#
# new xmax = len + -xmin
# = len + -ymin
# new xmin = - xmax
# new ymax = 2len + (-ymin) only candidate
# new ymin = -(ymax-len)
#
# xmax,xmin alternate
# ymax-len,ymin alternate
my $xmin = 0;
my $xmax = 0;
my $ymin = 0;
my $ymax = 0;
my $len = 1;
my $exp = 8;
print "level xmin xmax xsize | ymin ymax ysize\n";
for (0 .. $exp) {
printf "%2d %-10s %-10s = %-10s | %-10s %-10s = %-10s\n",
$_,
to_bin($xmin),to_bin($xmax), to_bin(-$xmin+$xmax),
to_bin($ymin),to_bin($ymax), to_bin(-$ymin+$ymax);
my @xmax_candidates = ($ymax, # seg 0 across
$len-$xmin, # seg 1 side <---
$len-$ymin, # seg 2 before <---
);
my $xmax_seg = max_index(@xmax_candidates);
my $xmax_candstr = join(',',@xmax_candidates);
my @xmin_candidates = ($ymin, # seg 0 before
-($ymax-$len), # seg 2 across
-$xmax, # seg 3 side <---
);
my $xmin_seg = min_index(@xmin_candidates);
my $xmin_candstr = join(',',@xmin_candidates);
my @ymin_candidates = (-$xmax, # seg 0 side <---
-($ymax-$len)); # seg 1 extend
my $ymin_seg = min_index(@ymin_candidates);
my $ymin_candstr = join(',',@ymin_candidates);
print "$_ xmax ${xmax_seg}of$xmax_candstr xmin ${xmin_seg}of$xmin_candstr ymin ${ymin_seg}of$ymin_candstr\n";
($xmax,$xmin, $ymax,$ymin)
= (
# xmax
max ($ymax, # seg 0 across
$len-$xmin, # seg 1 side
$len-$ymin, # seg 2 before
),
# xmin
min ($ymin, # seg 0 before
$len-$ymax, # seg 2 across
-$xmax, # seg 3 side
),
# ymax
2*$len-$ymin, # seg 3 before
# ymin
min(-$xmax, # seg 0 side
-($ymax-$len))); # seg 1 extend
### assert: $xmin <= 0
### assert: $ymin <= 0
### assert: $xmax >= 0
### assert: $ymax >= 0
$len *= 2;
}
print 3*$xmin/$len+.001," / 3\n";
print 6*$xmax/$len+.001," / 6\n";
print 3*$ymin/$len+.001," / 3\n";
print 3*$ymax/$len+.001," / 3\n";
exit 0;
sub min_index {
my $min_value = $_[0];
my $ret = 0;
foreach my $i (1 .. $#_) {
my $next = $_[$i];
if ($next == $min_value) {
$ret .= ",$i";
} elsif ($next < $min_value) {
$ret = $i;
$min_value = $next;
}
}
return $ret;
}
sub max_index {
### max_index(): @_
my $max_value = $_[0];
my $ret = 0;
foreach my $i (1 .. $#_) {
my $next = $_[$i];
### $next
if ($next == $max_value) {
### append ...
$ret .= ",$i";
} elsif ($next > $max_value) {
### new max ...
$ret = $i;
$max_value = $next;
}
}
return $ret;
}
}
{
# A088431 and A007400 continued fraction
require Math::ContinuedFraction;
require Math::NumSeq::PlanePathTurn;
require Math::NumSeq::GolayRudinShapiro;
require Math::NumSeq::OEIS;
my @runlengths = (0,1);
# my $seq = Math::NumSeq::PlanePathTurn->new(planepath=>'DragonCurve');
my $seq = Math::NumSeq::GolayRudinShapiro->new;
# my $seq = Math::NumSeq::OEIS->new (anum => 'A203531');
my (undef, $prev) = $seq->next;
my $count = 1;
while (@runlengths < 50) {
my (undef, $turn) = $seq->next;
if ($turn != $prev) {
push @runlengths, $count * 2;
$count = 0;
$prev = $turn;
}
$count++;
}
# @runlengths = (0, 1, 4, 2, 4, 4, 6, 4, 2, 4, 6, 2, 4, 6, 4, 4, 2, 4, 6, 2, 4, 4, 6, 4,
# 2, 6, 4, 2, 4, 6, 4, 4, 2, 4, 6, 2, 4, 4, 6, 4, 2, 4, 6, 2, 4, 6, 4, 4,
# 2, 6, 4, 2, 4, 4, 6, 4, 2, 6, 4, 2, 4, 6, 4, 4, 2, 4, 6, 2, 4, 4, 6, 4,
# 2, 4, 6, 2, 4, 6, 4, 4, 2, 4, 6, 2, 4, 4, 6, 4, 2, 6, 4, 2, 4, 6, 4, 4,
# );
my $cf = Math::ContinuedFraction->new(\@runlengths);
my $cfstr = $cf->to_ascii;
print "cf $cfstr\n";
foreach my $i (1 .. $#runlengths) {
my ($num, $den) = $cf->convergent($i);
my $numstr = $num->as_bin;
$numstr =~ s/^0b//;
my $denstr = $den->as_bin;
$denstr =~ s/^0b//;
# printf "%3d %-40.70s\n", $i, $numstr;
# printf " %-40.70s\n", $denstr;
my $approx = ($num << 256) / $den;
my $bits = $approx->as_bin;
$bits =~ s/^0b//;
print "approx: $bits\n";
}
my ($num, $den) = $cf->convergent($#runlengths);
my $approx = $num->numify / $den->numify;
print "$approx\n";
$num *= Math::BigInt->new(2) ** 70;
$num /= $den;
my $bits = $num->as_bin;
$bits =~ s/^0b//;
print "d: $bits\n";
exit 0;
}
# n_to_xy ...
# {
# # low to high
# my $rev = 0;
# my @rev;
# foreach my $digit (reverse @digits) {
# push @rev, $rev;
# $rev ^= $digit;
# }
# ### @digits
# my $x = 0;
# my $y = 0;
# my $dy = $rot & 1;
# my $dx = ! $dy;
# if ($rot & 2) {
# $dx = -$dx;
# $dy = -$dy;
# }
# $rev = 0;
# foreach my $digit (@digits) {
# ### at: "$x,$y dxdy=$dx,$dy"
# my $rev = shift @rev;
# if ($digit) {
# if ($rev) {
# ($x,$y) = (-$y,$x); # rotate +90
# } else {
# ($x,$y) = ($y,-$x); # rotate -90
# }
# $x += $dx;
# $y += $dy;
# $rev = $digit;
# }
# # multiply i+1, ie. (dx,dy) = (dx + i*dy)*(i+1)
# ($dx,$dy) = ($dx-$dy, $dx+$dy);
# }
# ### final: "$x,$y dxdy=$dx,$dy"
# return ($x,$y);
# }
{
# inner rectangle touching
# | |
# 751-750 735-734 431-
#
#
#
# 382-383
# |
# 380-385-384
# |
# 379-386-387
# |
# 376-377-388
# |
# 375-374 371-
#
# 368
#
# 367-
#
# 9-- 8 5-- 4
# | |
# 10--11-- 6 3-- 2 190-191
# | |
# 17--16 13--12 0-- 1 188-193-192
# | | |
# 18--19- 22--23 187-194-195
# | | |
# 20- 25--24 184-185-196
# | |
# 26--27 46--47 94--95 183-182-179-
# | | | |
# 33--32 29- 44- 49--48 92- 97--96 108-113-176
# | | | | |
# 34--35- 38- 43- 50--51 54- 91- 98--99 102-107-114-175-
# | | | | | | |
# 36--37 40--41 52- 57- 88--89-100-101 104-105 116
# | |
# 58- 87--86- 83--82
# | |
# 65--64 61- 76--77 80--81 129-128
# | | |
# 66--67- 70- 75--74 130-131-134
# | | |
# 68--69 72--73 132
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
foreach my $k (0 .. 5) {
my $level = 2*$k;
my $Nlevel = 2**$level;
print "k=$k level=$level Nlevel=$Nlevel\n";
# my $c1x = 2**$k - calc_Wmax($k); # <--
# my $c1y = 2**$k + calc_Wmin($k); # <--
# my $c2x = 2**($k+1) - calc_Wmax($k+1);
# my $c2y = 2**($k+1) + calc_Wmin($k+1);
# my $c3x = 2**($k+2) - calc_Wmax($k+2); # <--
# my $c3y = 2**($k+2) + calc_Wmin($k+2); # <--
my $c1x = calc_Wouter($k); # <--
my $c1y = calc_Louter($k); # <--
my $c2x = calc_Wouter($k+1);
my $c2y = calc_Louter($k+1);
my $c3x = calc_Wouter($k+2); # <--
my $c3y = calc_Louter($k+2); # <--
my $step_c2x = 2*$c1x - !($k&1);
unless ($step_c2x == $c2x) {
warn "step X $step_c2x != $c2x";
}
my $step_c2y = 2*$c1y - ($k&1);
unless ($step_c2y == $c2y) {
warn "step Y $step_c2y != $c2y";
}
my $step_c3x = 4 * $c1x - 2 + ($k&1);
unless ($step_c3x == $c3x) {
warn "step X $step_c3x != $c3x";
}
my $step_c3y = 4 * $c1y - 1 - ($k & 1);
unless ($step_c3y == $c3y) {
warn "step Y $step_c3y != $c3y";
}
unless ($c1y == $c2x) {
warn "diff $c1y $c2x";
}
unless ($c2y == $c3x) {
warn "diff $c2y $c3x";
}
my $xmax = $c1x;
my $ymax = $c1y;
my $xmin = -$c3x;
my $ymin = -$c3y;
print " C1 x=$xmax,y=$ymax C2 x=$c2x,y=$c2y C3 x=$c3x,y=$c3y\n";
print " out x=$xmin..$xmax y=$ymin..$ymax\n";
foreach (1 .. $k) {
print " rotate\n";
($xmax, # rotate +90
$ymax,
$xmin,
$ymin) = (-$ymin,
$xmax,
-$ymax,
$xmin);
}
print " out x=$xmin..$xmax y=$ymin..$ymax\n";
my $in_xmax = $xmax - 1;
my $in_xmin = $xmin + 1;
my $in_ymax = $ymax - 1;
my $in_ymin = $ymin + 1;
print " in x=$in_xmin..$in_xmax y=$in_ymin..$in_ymax\n";
# inner edges, Nlevel or higher is bad
foreach my $y ($in_ymax, $in_ymin) {
foreach my $x ($in_xmin .. $in_xmax) {
foreach my $n ($path->xy_to_n_list ($x, $y)) {
if ($n >= $Nlevel) {
print "$n $x,$y horiz ***\n";
}
}
}
}
# inner edges, Nlevel or higher is bad
foreach my $x ($in_xmax, $in_xmin) {
foreach my $y ($in_ymin .. $in_ymax) {
foreach my $n ($path->xy_to_n_list ($x, $y)) {
if ($n >= $Nlevel) {
print "$n $x,$y vert ***\n";
}
}
}
}
# outer edges, Nlevel or higher touched
my $touch = 0;
foreach my $y ($ymax, $ymin) {
foreach my $x ($xmin .. $xmax) {
foreach my $n ($path->xy_to_n_list ($x, $y)) {
if ($n >= $Nlevel) {
$touch++;
}
}
}
}
# inner edges, Nlevel or higher is bad
foreach my $x ($xmax, $xmin) {
foreach my $y ($ymin .. $ymax) {
foreach my $n ($path->xy_to_n_list ($x, $y)) {
if ($n >= $Nlevel) {
$touch++;
}
}
}
}
my $diff_touch = ($touch == 0 ? ' ***' : '');
print " touch $touch$diff_touch\n";
}
exit 0;
sub calc_Louter {
my ($k) = @_;
# Louter = 2^k - abs(Lmin)
# = 2^k - (2^k - 1 - (k&1))/3
# = (3*2^k - (2^k - 1 - (k&1)))/3
# = (3*2^k - 2^k + 1 + (k&1))/3
# = (2*2^k + 1 + (k&1))/3
return (2*2**$k + 1 + ($k&1)) / 3;
# return 2**$k + calc_Lmin($k);
}
sub calc_Wouter {
my ($k) = @_;
# Wouter = 2^k - Wmax
# = 2^k - (2*2^k - 2 + (k&1)) / 3
# = (3*2^k - (2*2^k - 2 + (k&1))) / 3
# = (3*2^k - 2*2^k + 2 - (k&1)) / 3
# = (2^k + 2 - (k&1)) / 3
return (2**$k + 2 - ($k&1)) / 3;
# return 2**$k - calc_Wmax($k);
}
sub calc_Lmax {
my ($k) = @_;
# Lmax = (7*2^k - 4)/6 if k even
# (7*2^k - 2)/6 if k odd
if ($k & 1) {
return (7*2**$k - 2) / 6;
} else {
return (7*2**$k - 4) / 6;
}
}
sub calc_Lmin {
my ($k) = @_;
# Lmin = - (2^k - 1)/3 if k even
# - (2^k - 2)/3 if k odd
# = - (2^k - 2 - (k&1))/3
if ($k & 1) {
return - (2**$k - 2) / 3;
} else {
return - (2**$k - 1) / 3;
}
}
sub calc_Wmax {
my ($k) = @_;
# Wmax = (2*2^k - 1) / 3 if k odd
# (2*2^k - 2) / 3 if k even
# = (2*2^k - 2 + (k&1)) / 3
if ($k & 1) {
return (2*2**$k - 1) / 3;
} else {
return (2*2**$k - 2) / 3;
}
}
sub calc_Wmin {
my ($k) = @_;
return calc_Lmin($k);
}
}
{
# inner Wmin/Wmax
foreach my $k (0 .. 10) {
my $wmax = calc_Wmax($k);
my $wmin = calc_Wmin($k);
my $submax = 2**$k - $wmax;
my $submin = 2**$k + $wmin;
printf "%2d %4d %4d %4d %4d\n",
$k, abs($wmin), $wmax, $submax, $submin;
# printf "%2d %8b %8b %8b %8b\n",
# $k, abs($wmin), $wmax, $submax, $submin;
}
exit 0;
}
{
# width,height extents
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my @xend = (1);
my @yend = (0);
my @xmin = (0);
my @xmax = (1);
my @ymin = (0);
my @ymax = (0);
extend();
sub extend {
my $xend = $xend[-1];
my $yend = $yend[-1];
($xend,$yend) = ($xend-$yend, # rotate +45
$xend+$yend);
push @xend, $xend;
push @yend, $yend;
my $xmax = $xmax[-1];
my $xmin = $xmin[-1];
my $ymax = $ymax[-1];
my $ymin = $ymin[-1];
### assert: $xmax >= $xmin
### assert: $ymax >= $ymin
# ### at: "end=$xend,$yend $xmin..$xmax $ymin..$ymax"
push @xmax, max($xmax, $xend + $ymax);
push @xmin, min($xmin, $xend + $ymin);
push @ymax, max($ymax, $yend - $xmin);
push @ymin, min($ymin, $yend - $xmax);
}
my $level = 0;
my $n_level = 1;
my $n = 0;
my $xmin = 0;
my $xmax = 0;
my $ymin = 0;
my $ymax = 0;
my $prev_r = 1;
for (;;) {
my ($x,$y) = $path->n_to_xy($n);
$xmin = min($xmin,$x);
$xmax = max($xmax,$x);
$ymin = min($ymin,$y);
$ymax = max($ymax,$y);
if ($n == $n_level) {
my $width = $xmax - $xmin + 1;
my $height = $ymax - $ymin + 1;
my $r = ($width/2)**2 + ($height/2)**2;
my $rf = $r / $prev_r;
my $xmin2 = to_bin($xmin);
my $ymin2 = to_bin($ymin);
my $xmax2 = to_bin($xmax);
my $ymax2 = to_bin($ymax);
my $xrange= sprintf "%9s..%9s", $xmin2, $xmax2;
my $yrange= sprintf "%9s..%9s", $ymin2, $ymax2;
printf "%2d n=%-7d %19s %19s r=%.2f (%.3f)\n",
$level, $n, $xrange, $yrange, $r, $rf;
extend();
$xrange="$xmin[$level]..$xmax[$level]";
$yrange="$ymin[$level]..$ymax[$level]";
# printf " %9s %9s\n",
# $xrange, $yrange;
$level++;
$n_level *= 2;
$prev_r = $r;
last if $level > 30;
}
$n++;
}
exit 0;
sub to_bin {
my ($n) = @_;
return ($n < 0 ? '-' : '') . sprintf('%b', abs($n));
}
}
{
# A088431
require Math::ContinuedFraction;
require Math::BigInt;
require Math::BigRat;
my $half = Math::BigRat->new('1/2');
my $rat = Math::BigRat->new('1');
for (my $exp = 1; $exp <= 16; $exp *= 2) {
$rat += $half ** $exp;
}
print "$rat\n";
my $num = $rat->numerator;
my $den = $rat->denominator;
print "num ",$num->as_bin,"\n";
print "den ",$den->as_bin,"\n";
my $cf = Math::ContinuedFraction->from_ratio($num,$den);
my $cfstr = $cf->to_ascii;
my $cfaref = $cf->to_array;
my $cflen = scalar(@$cfaref);
print "$cflen $cfstr\n";
$,=',';
foreach (@$cfaref) { $_ /= 2 }
print @$cfaref,"\n";
exit 0;
}
{
# diagonal
#
# |---8
# |
# v
# 6<--
# |
# |
# 0 |---4
# | |
# | v
# |-->2
#
# new xmax = ymax or -ymin or 2L-xmin
# new xmin = ymin
# new ymax = 2L-ymin
# new ymin = -xmax or -ymax same
my $xmax = 1;
my $xmin = 0;
my $ymax = 1;
my $ymin = 0;
my $len = 1;
my $exp = 8;
for (1 .. $exp) {
printf "%2d %-18s %-18s %-18s %-18s\n",
$_, to_bin($xmin),to_bin($xmax), to_bin($ymin),to_bin($ymax);
($xmax,
$xmin,
$ymax,
$ymin)
=
(max($ymax, -$ymin, 2*$len-$xmin),
min($ymin),
2*$len-$ymin,
min(-$xmax,-$ymax));
### assert: $xmin <= 0
### assert: $ymin <= 0
### assert: $xmax >= 0
### assert: $ymax >= 0
$len *= 2;
}
print 3*$xmin/$len+.001," / 3\n";
print 6*$xmax/$len+.001," / 6\n";
print 3*$ymin/$len+.001," / 3\n";
print 3*$ymax/$len+.001," / 3\n";
}
{
# A073089 midpoint vertical/horizontal formula
require Math::NumSeq::OEIS::File;
my $A073089 = Math::NumSeq::OEIS::File->new (anum => 'A073089');
my $A014577 = Math::NumSeq::OEIS::File->new (anum => 'A014577'); # 0=left n=0
my $A014707 = Math::NumSeq::OEIS::File->new (anum => 'A014707'); # 1=left
my $A038189 = Math::NumSeq::OEIS::File->new (anum => 'A038189');
my $A082410 = Math::NumSeq::OEIS::File->new (anum => 'A082410');
my $A000035 = Math::NumSeq::OEIS::File->new (anum => 'A000035'); # n mod 2
my $count = 0;
foreach my $n (0 .. 1000) {
my $got = $A073089->ith($n) // next;
# works except for n=1
# my $turn = $A014707->ith($n-2) // next;
# my $flip = $A000035->ith($n-2) // next;
# my $calc = $turn ^ $flip;
# works
# my $turn = $A014577->ith($n-2) // next;
# my $flip = $A000035->ith($n-2) // next;
# my $calc = $turn ^ $flip ^ 1;
# so A073089(n) = A082410(n) xor A000035(n) xor 1
my $turn = $A082410->ith($n) // next;
my $flip = $A000035->ith($n) // next;
my $calc = $turn ^ $flip ^ 1;
if ($got != $calc) {
print "wrong $n got=$got calc=$calc\n";
}
$count++;
}
print "count $count\n";
exit 0;
}
{
# doublings
require Math::PlanePath::DragonCurve;
require Math::BaseCnv;
my $path = Math::PlanePath::DragonCurve->new;
my %seen;
for (my $n = 0; $n < 2000; $n++) {
my ($x,$y) = $path->n_to_xy($n);
my $key = "$x,$y";
push @{$seen{$key}}, $n;
if (@{$seen{$key}} == 2) {
my @v2;
my $aref = delete $seen{$key};
my $sum = 0;
foreach my $v (@$aref) {
$sum += $v;
my $v2 = Math::BaseCnv::cnv($v,10,2);
push @v2, $v2;
printf "%4s %12s\n", $v, $v2;
}
printf "%4s %12b sum\n", $sum, $sum;
my $diff = abs($aref->[0]-$aref->[1]);
printf "%4s %12b diff\n", $diff, $diff;
my $lenmatch = 0;
foreach my $i (1 .. length($v2[0])) {
my $want = substr ($v2[0], -$i);
if ($v2[1] =~ /$want$/) {
next;
} else {
$lenmatch = $i-1;
last;
last;
}
}
my $zeros = ($v2[0] =~ /(0*)$/ && $1);
my $lenzeros = length($zeros);
my $same = ($lenmatch == $lenzeros+2 ? "same" : "diff");
print "low same $lenmatch zeros $lenzeros $same\n";
my $new = $aref->[0];
my $first_bit = my $bit = 2 * 2**$lenzeros;
my $change = 0;
while ($bit <= 2*$aref->[0]) {
### $bit
### $change
if ($change) {
$new ^= $bit;
$change = ! ($aref->[0] & $bit);
} else {
$change = ($aref->[0] & $bit);
}
$bit *= 2;
}
my $new2 = Math::BaseCnv::cnv($new,10,2);
if ($new != $aref->[1]) {
print "flip wrong first $first_bit last $bit to $new $new2\n";
}
print "\n";
}
}
exit 0;
}
{
# DragonMidpoint abs(dY) sequence
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => 'DragonMidpoint',
delta_type => 'dY');
foreach (0 .. 64) {
my ($i,$value) = $seq->next;
my $p = $i+2;
# while ($p && ! ($p&1)) {
# $p/=2;
# }
my $v = calc_n_midpoint_vert($i+1);
printf "%d %d %7b\n", abs($value), $v, $p;
}
exit 0;
}
{
# DragonMidpoint abs(dY) sequence
require Math::PlanePath::DragonMidpoint;
my $path = Math::PlanePath::DragonMidpoint->new;
foreach my $n (0 .. 64) {
my ($x,$y) = $path->n_to_xy($n);
my ($nx,$ny) = $path->n_to_xy($n+1);
if ($nx == $x) {
my $p = $n+2;
# while ($p && ! ($p&1)) {
# $p/=2;
# }
my $v = calc_n_midpoint_vert($n);
printf "%d %7b\n", $v, $p;
}
}
exit 0;
sub calc_n_midpoint_vert {
my ($n) = @_;
if ($n < 0) { return 0; }
my $vert = ($n & 1);
my $right = calc_n_turn($n);
return ((($vert && !$right)
|| (!$vert && $right))
? 0
: 1);
}
# return 0 for left, 1 for right
sub calc_n_turn {
my ($n) = @_;
my ($mask,$z);
$mask = $n & -$n; # lowest 1 bit, 000100..00
$z = $n & ($mask << 1); # the bit above it
my $turn = ($z == 0 ? 0 : 1);
# printf "%b %b %b %d\n", $n,$mask, $z, $turn;
return $turn;
}
}
{
# xy absolute direction nsew
require Math::PlanePath::DragonCurve;
my @array;
my $arms = 4;
my $path = Math::PlanePath::DragonCurve->new (arms => $arms);
my $width = 20;
my $height = 20;
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$width+2,$height+2);
print "n_hi $n_hi\n";
for my $n (0 .. 20*$n_hi) {
# next if ($n % 4) == 0;
# next if ($n % 4) == 1;
# next if ($n % 4) == 2;
# next if ($n % 4) == 3;
my ($x,$y) = $path->n_to_xy($n);
next if $x < 0 || $y < 0 || $x > $width || $y > $height;
my ($nx,$ny) = $path->n_to_xy($n+$arms);
if ($ny == $y+1) {
$array[$x][$y] .= ($n & 1 ? "n" : "N");
}
if ($ny == $y-1) {
$array[$x][$y] .= ($n & 1 ? "s" : "S");
}
# if ($nx == $x+1) {
# $array[$x][$y] .= "w";
# }
# if ($nx == $x-1) {
# $array[$x][$y] .= "e";
# }
}
foreach my $y (reverse 0 .. $height) {
foreach my $x (0 .. $width) {
my $v = $array[$x][$y]//'';
$v = sort_str($v);
printf "%3s", $v;
}
print "\n";
}
exit 0;
}
{
# xy absolute direction
require Image::Base::Text;
require Math::PlanePath::DragonCurve;
my $arms = 1;
my $path = Math::PlanePath::DragonCurve->new (arms => $arms);
my $width = 20;
my $height = 20;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$width+2,$height+2);
print "n_hi $n_hi\n";
for my $n (0 .. $n_hi) {
my ($x,$y) = $path->n_to_xy($n);
next if $x < 0 || $y < 0 || $x >= $width || $y >= $height;
my ($nx,$ny) = $path->n_to_xy($n+$arms);
# if ($nx == $x+1) {
# $image->xy($x,$y,$n&3);
# }
# if ($ny == $y+1) {
# $image->xy($x,$y,$n&3);
# }
if ($ny == $y+1 || $ny == $y-1) {
# $image->xy($x,$y,$n&3);
$image->xy($x,$y,'|');
}
if ($nx == $x+1 || $nx == $x-1) {
# $image->xy($x,$y,$n&3);
$image->xy($x,$y,'-');
}
}
$image->save('/dev/stdout');
exit 0;
}
{
# Rounded and Midpoint equivalence table
require Math::PlanePath::DragonRounded;
require Math::PlanePath::DragonMidpoint;
my @yx_rtom_dx;
my @yx_rtom_dy;
foreach my $arms (1 .. 4) {
### $arms
my $rounded = Math::PlanePath::DragonRounded->new (arms => $arms);
my $midpoint = Math::PlanePath::DragonMidpoint->new (arms => $arms);
my %seen;
foreach my $n (0 .. 5000) {
my ($x,$y) = $rounded->n_to_xy($n) or next;
my ($mx,$my) = $midpoint->n_to_xy($n);
my $dx = ($x - floor($x/3)) - $mx;
my $dy = ($y - floor($y/3)) - $my;
if (defined $yx_rtom_dx[$y%6][$x%6]
&& $yx_rtom_dx[$y%6][$x%6] != $dx) {
die "oops";
}
if (defined $yx_rtom_dy[$y%6][$x%6]
&& $yx_rtom_dy[$y%6][$x%6] != $dy) {
die "oops";
}
$yx_rtom_dx[$y%6][$x%6] = $dx;
$yx_rtom_dy[$y%6][$x%6] = $dy;
}
print_6x6(\@yx_rtom_dx);
print_6x6(\@yx_rtom_dy);
foreach my $n (0 .. 1000) {
my ($x,$y) = $rounded->n_to_xy($n) or next;
my $mx = $x-floor($x/3) - $yx_rtom_dx[$y%6][$x%6];
my $my = $y-floor($y/3) - $yx_rtom_dy[$y%6][$x%6];
my $m = $midpoint->xy_to_n($mx,$my);
my $good = (defined $m && $n == $m ? "good" : "bad");
printf "n=%d xy=%d,%d -> mxy=%d,%d m=%s %s\n",
$n, $x,$y,
$mx,$my, $m//'undef',
$good;
}
}
exit 0;
sub print_6x6 {
my ($aref) = @_;
foreach my $y (0 .. 5) {
if ($y == 0) {
print "[[";
} else {
print " [";
}
foreach my $x (0 .. 5) {
my $v = $aref->[$y][$x] // 'undef';
printf "%5s", $v;
if ($x != 5) { print ", " }
}
if ($y == 5) {
print "] ]\n";
} else {
print "]\n";
}
}
}
}
{
# Rounded and Midpoint equivalence checks
require Math::PlanePath::DragonRounded;
require Math::PlanePath::DragonMidpoint;
my @yx_rtom_dx;
my @yx_rtom_dy;
foreach my $arms (1 .. 4) {
print "\narms=$arms\n";
my $rounded = Math::PlanePath::DragonRounded->new (arms => $arms);
my $midpoint = Math::PlanePath::DragonMidpoint->new (arms => $arms);
foreach my $y (reverse -10 .. 10) {
foreach my $x (-7 .. 7) {
my $d = '';
my $n = $rounded->xy_to_n($x,$y);
if (defined $n) {
my ($mx,$my) = $midpoint->n_to_xy($n);
my $dx = ($x - floor($x/3)) - $mx;
my $dy = ($y - floor($y/3)) - $my;
$d = "$dx,$dy";
} elsif ($x==0&&$y==0) {
$d = '+';
}
printf "%5s", $d;
}
print "\n";
}
}
exit 0;
}
{
# A059125 "dragon-like"
require MyOEIS;
my ($drag_values) = MyOEIS::read_values('A014707');
my ($like_values) = MyOEIS::read_values('A059125');
my @diff = map {$drag_values->[$_] == $like_values->[$_] ? '_' : 'x' }
0 .. 80;
print @{$drag_values}[0..70],"\n";
print @{$like_values}[0..70],"\n";
print @diff[0..70],"\n";
exit 0;
}
{
# Curve xy to n by midpoint
require Math::PlanePath::DragonCurve;
require Math::PlanePath::DragonMidpoint;
require Math::BaseCnv;
foreach my $arms (3) {
### $arms
my $curve = Math::PlanePath::DragonCurve->new (arms => $arms);
my $midpoint = Math::PlanePath::DragonMidpoint->new (arms => $arms);
my %seen;
for (my $n = 0; $n < 50; $n++) {
my ($x,$y) = $curve->n_to_xy($n);
my $list = '';
my $found = '';
DX: foreach my $dx (-1,0) {
foreach my $dy (0,1) {
# my ($x,$y) = ($x-$y,$x+$y); # rotate +45 and mul sqrt(2)
my ($x,$y) = ($x+$y,$y-$x); # rotate -45 and mul sqrt(2)
my $m = $midpoint->xy_to_n($x+$dx,$y+$dy) // next;
$list .= " $m";
if ($m == $n) {
$found = "$dx,$dy";
# last DX;
}
}
}
printf "n=%d xy=%d,%d got %s %s\n",
$n,$x,$y,
$found, $list;
$seen{$found} = 1;
}
$,=' ';
print sort keys %seen,"\n";
}
exit 0;
# (x+iy)*(i+1) = (x-y)+(x+y)i # +45
# (x+iy)*(-i+1) = (x+y)+(y-x)i # -45
}
{
# x axis absolute direction
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new (arms => 4);
my $width = 30;
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$width+2,0);
my (@enter, @leave);
print "n_hi $n_hi\n";
for my $n (0 .. $n_hi) {
my ($x,$y) = $path->n_to_xy($n);
if ($y == 0 && $x >= 0) {
{
my ($nx,$ny) = $path->n_to_xy($n+4);
if ($ny > $y) {
$leave[$x] .= 'u';
}
if ($ny < $y) {
$leave[$x] .= 'd';
}
if ($nx > $x) {
$leave[$x] .= 'r';
}
if ($nx < $x) {
$leave[$x] .= 'l';
}
}
if ($n >= 4) {
my ($px,$py) = $path->n_to_xy($n-4);
if ($y > $py) {
$enter[$x] .= 'u';
}
if ($y < $py) {
$enter[$x] .= 'd';
}
if ($x > $px) {
$enter[$x] .= 'r';
}
if ($x < $px) {
$enter[$x] .= 'l';
}
}
}
}
foreach my $x (0 .. $width) {
print "$x ",sort_str($enter[$x])," ",sort_str($leave[$x]),"\n";
}
sub sort_str {
my ($str) = @_;
if (! defined $str) {
return '-';
}
return join ('', sort split //, $str);
}
exit 0;
}
{
# Midpoint xy to n
require Math::PlanePath::DragonMidpoint;
require Math::BaseCnv;
my @yx_adj_x = ([0,1,1,0],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]);
my @yx_adj_y = ([0,0,1,1],
[0,0,1,1],
[1,1,0,0],
[1,1,0,0]);
sub xy_to_n {
my ($self, $x,$y) = @_;
my $n = ($x * 0 * $y) + 0; # inherit bignum 0
my $npow = $n + 1; # inherit bignum 1
while (($x != 0 && $x != -1) || ($y != 0 && $y != 1)) {
# my $ax = ((($x+1) ^ ($y+1)) >> 1) & 1;
# my $ay = (($x^$y) >> 1) & 1;
# ### assert: $ax == - $yx_adj_x[$y%4]->[$x%4]
# ### assert: $ay == - $yx_adj_y[$y%4]->[$x%4]
my $y4 = $y % 4;
my $x4 = $x % 4;
my $ax = $yx_adj_x[$y4]->[$x4];
my $ay = $yx_adj_y[$y4]->[$x4];
### at: "$x,$y n=$n axy=$ax,$ay bit=".($ax^$ay)
if ($ax^$ay) {
$n += $npow;
}
$npow *= 2;
$x -= $ax;
$y -= $ay;
### assert: ($x+$y)%2 == 0
($x,$y) = (($x+$y)/2, # rotate -45 and divide sqrt(2)
($y-$x)/2);
}
### final: "xy=$x,$y"
my $arm;
if ($x == 0) {
if ($y) {
$arm = 1;
### flip ...
$n = $npow-1-$n;
} else { # $y == 1
$arm = 0;
}
} else { # $x == -1
if ($y) {
$arm = 2;
} else {
$arm = 3;
### flip ...
$n = $npow-1-$n;
}
}
### $arm
my $arms_count = $self->arms_count;
if ($arm > $arms_count) {
return undef;
}
return $n * $arms_count + $arm;
}
foreach my $arms (4,3,1,2) {
### $arms
my $path = Math::PlanePath::DragonMidpoint->new (arms => $arms);
for (my $n = 0; $n < 50; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or next;
my $rn = xy_to_n($path,$x,$y);
my $good = '';
if (defined $rn && $rn == $n) {
$good .= "good N";
}
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $rn2 = Math::BaseCnv::cnv($rn,10,2);
printf "n=%d xy=%d,%d got rn=%d %s\n",
$n,$x,$y,
$rn,
$good;
}
}
exit 0;
}
{
# xy modulus
require Math::PlanePath::DragonMidpoint;
my $path = Math::PlanePath::DragonMidpoint->new;
my %seen;
for (my $n = 0; $n < 1024; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or next;
my $k = ($x+$y) & 15;
# $x &= 3; $y &= 3; $k = "$x,$y";
$seen{$k} = 1;
}
### %seen
exit 0;
}
{
# arm xy modulus
require Math::PlanePath::DragonMidpoint;
my $path = Math::PlanePath::DragonMidpoint->new (arms => 4);
my %seen;
for (my $n = 0; $n < 1024; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or next;
$x &= 3;
$y &= 3;
$seen{$n&3}->{"$x,$y"} = 1;
}
### %seen
exit 0;
}
{
# xy to n
require Math::PlanePath::DragonMidpoint;
require Math::BaseCnv;
my @yx_adj_x = ([0,-1,-1,0],
[-1,0,0,-1],
[-1,0,0,-1],
[0,-1,-1,0]);
my @yx_adj_y = ([0,0,-1,-1],
[0,0,-1,-1],
[-1,-1,0,0],
[-1,-1,0,0]);
my $path = Math::PlanePath::DragonMidpoint->new (); # (arms => 4);
for (my $n = 0; $n < 50; $n++) {
my ($x,$y) = $path->n_to_xy($n)
or next;
($x,$y) = (-$y,$x+1); # rotate +90
# ($x,$y) = (-$x-1,-$y+1); # rotate 180
# my $rot = 1;
# if ($rot & 2) {
# $x -= 1;
# }
# if (($rot+1) & 2) {
# # rot 1 or 2
# $y += 1;
# }
### xy: "$n $x,$y adj ".$yx_adj_x[$y&3]->[$x&3]." ".$yx_adj_y[$y&3]->[$x&3]
my $rx = $x;
my $ry = $y;
# if (((($x+1)>>1)&1) ^ ((($y-1)&2))) {
# $rx--;
# }
# if (((($x-1)>>1)&1) ^ ((($y+1)&2))) {
# $ry--;
# }
my $ax = ((($x+1) ^ ($y+1)) >> 1) & 1;
my $ay = (($x^$y) >> 1) & 1;
### assert: $ax == - $yx_adj_x[$y&3]->[$x&3]
### assert: $ay == - $yx_adj_y[$y&3]->[$x&3]
# $rx += $yx_adj_x[$y&3]->[$x&3];
# $ry += $yx_adj_y[$y&3]->[$x&3];
$rx -= $ax;
$ry -= $ay;
($rx,$ry) = (($rx+$ry)/2,
($ry-$rx)/2);
### assert: $rx == int($rx)
### assert: $ry == int($ry)
# my $arm = $n & 3;
# my $nbit = ($path->arms_count == 4 ? ($n>>2)&1 : $n&1);
# my $bit = $ax ^ $ay ^ ($arm&0) ^ (($arm>>1)&1);
my $nbit = $n&1;
my $bit = $ax ^ $ay;
my $rn = $path->xy_to_n($ry-1,-$rx); # rotate -90
# my $rn = $path->xy_to_n(-$rx-1,-$ry+1); # rotate 180
my $good = '';
if (defined $rn && $rn == int($n/2)) {
$good .= "good N";
}
if ($nbit == $bit) {
$good .= " good bit";
}
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $rn2 = Math::BaseCnv::cnv($rn,10,2);
printf "%d %d (%8s %8s) bit=%d,%d %d,%d %s\n",
$n,$rn, $n2,$rn2,
$nbit,$bit,
$x,$y, $good;
}
exit 0;
}
{
require Image::Base::Text;
my $width = 79;
my $height = 50;
my $ox = $width/2;
my $oy = $height/2;
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $store = sub {
my ($x,$y,$c) = @_;
# $x *= 2;
# $y *= 2;
$x += $ox;
$y += $oy;
if ($x >= 0 && $y >= 0 && $x < $width && $y < $height) {
my $o = $image->xy($x,$y);
# if (defined $o && $o ne ' ' && $o ne $c) {
# $c = '*';
# }
$image->xy($x,$y,$c);
} else {
die "$x,$y";
}
};
my ($x,$y);
for my $n (0 .. 2**8) {
($x,$y) = $path->n_to_xy($n);
# # (x+iy)/(i+1) = (x+iy)*(i-1)/2 = (-x-y)/2 + (x-y)/2
# if (($x+$y) % 2) { $x--; }
# ($x,$y) = ((-$x-$y)/2,
# ($x-$y)/2);
#
# # (x+iy)/(i+1) = (x+iy)*(i-1)/2 = (-x-y)/2 + (x-y)/2
# if (($x+$y) % 2) { $x--; }
# ($x,$y) = ((-$x-$y)/2,
# ($x-$y)/2);
# ($x,$y) = (-$y,$x); # rotate +90
$y = -$y;
$store->($x,$y,'*');
}
$store->($x,$y,'+');
$store->(0,0,'o');
$image->save('/dev/stdout');
exit 0;
}
{
# vs ComplexPlus
require Math::PlanePath::DragonCurve;
require Math::PlanePath::ComplexPlus;
require Math::BaseCnv;
my $dragon = Math::PlanePath::DragonCurve->new;
my $complex = Math::PlanePath::ComplexPlus->new;
for (my $n = 0; $n < 50; $n++) {
my ($x,$y) = $dragon->n_to_xy($n)
or next;
my $cn = $complex->xy_to_n($x,$y);
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $cn2 = (defined $cn ? Math::BaseCnv::cnv($cn,10,2) : 'undef');
printf "%8s %8s %d,%d\n", $n2, $cn2, $x,$y;
}
exit 0;
}
{
# turn
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $n = $path->n_start;
my ($n0_x, $n0_y) = $path->n_to_xy ($n);
$n++;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
my ($prev_dx, $prev_dy) = ($prev_x - $n0_x, $prev_y - $n0_y);
$n++;
my $pow = 4;
for ( ; $n < 128; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my $dx = ($x - $prev_x);
my $dy = ($y - $prev_y);
my $turn;
if ($prev_dx) {
if ($dy == $prev_dx) {
$turn = 0; # left
} else {
$turn = 1; # right
}
} else {
if ($dx == $prev_dy) {
$turn = 1; # right
} else {
$turn = 0; # left
}
}
($prev_dx,$prev_dy) = ($dx,$dy);
($prev_x,$prev_y) = ($x,$y);
print "$turn";
if ($n-1 == $pow) {
$pow *= 2;
print "\n";
}
}
print "\n";
exit 0;
}
{
# turn
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $n = 0;
my ($n0_x, $n0_y) = $path->n_to_xy ($n);
$n++;
my ($prev_x, $prev_y) = $path->n_to_xy ($n);
my ($prev_dx, $prev_dy) = ($prev_x - $n0_x, $prev_y - $n0_y);
$n++;
for ( ; $n < 40; $n++) {
my ($x, $y) = $path->n_to_xy ($n);
my $dx = ($x - $prev_x);
my $dy = ($y - $prev_y);
my $turn;
if ($prev_dx) {
if ($dy == $prev_dx) {
$turn = 0; # left
} else {
$turn = 1; # right
}
} else {
if ($dx == $prev_dy) {
$turn = 1; # right
} else {
$turn = 0; # left
}
}
### $n
### $prev_dx
### $prev_dy
### $dx
### $dy
# ### is: "$got[-1] at idx $#got"
($prev_dx,$prev_dy) = ($dx,$dy);
($prev_x,$prev_y) = ($x,$y);
my $zero = bit_above_lowest_zero($n-1);
my $one = bit_above_lowest_one($n-1);
print "$n $turn $one $zero\n";
# if ($turn != $bit) {
# die "n=$n got $turn bit $bit\n";
# }
}
print "n=$n ok\n";
sub bit_above_lowest_zero {
my ($n) = @_;
for (;;) {
if (($n % 2) == 0) {
last;
}
$n = int($n/2);
}
$n = int($n/2);
return ($n % 2);
}
sub bit_above_lowest_one {
my ($n) = @_;
for (;;) {
if (! $n || ($n % 2) != 0) {
last;
}
$n = int($n/2);
}
$n = int($n/2);
return ($n % 2);
}
exit 0;
}
{
# BigFloat log()
use Math::BigFloat;
my $b = Math::BigFloat->new(3)**64;
my $log = log($b);
my $log3 = $log/log(3);
# $b->blog(undef,100);
print "$b\n$log\n$log3\n";
exit 0;
}
{
# BigInt log()
use Math::BigInt;
use Math::BigFloat;
my $b = Math::BigInt->new(1025);
my $log = log($b);
$b->blog(undef,100);
print "$b $log\n";
exit 0;
}
{
require Image::Base::Text;
my $width = 132;
my $height = 50;
my $ox = $width/2;
my $oy = $height/2;
my $image = Image::Base::Text->new (-width => $width, -height => $height);
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $store = sub {
my ($x,$y,$c) = @_;
$x *= 2;
$x += $ox;
$y += $oy;
if ($x >= 0 && $y >= 0 && $x < $width && $y < $height) {
my $o = $image->xy($x,$y);
# if (defined $o && $o ne ' ' && $o ne $c) {
# $c = '*';
# }
$image->xy($x,$y,$c);
} else {
die "$x,$y";
}
};
my ($x,$y);
for my $n (0 .. 2**9) {
($x,$y) = $path->n_to_xy($n);
$y = -$y;
$store->($x,$y,'*');
}
$store->($x,$y,'+');
$store->(0,0,'+');
$image->save('/dev/stdout');
exit 0;
}
{
# Midpoint fracs
require Math::PlanePath::DragonMidpoint;
my $path = Math::PlanePath::DragonMidpoint->new;
for my $n (0 .. 64) {
my $frac = .125;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
my ($x,$y) = $path->n_to_xy($n+$frac);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
my $xm = $x1 + $frac*$dx;
my $ym = $y1 + $frac*$dy;
my $wrong = '';
if ($x != $xm) {
$wrong .= " X";
}
if ($y != $ym) {
$wrong .= " Y";
}
print "$n $dx,$dy $x, $y want $xm, $ym $wrong\n"
}
exit 0;
}
{
# min/max for level
require Math::PlanePath::DragonRounded;
my $path = Math::PlanePath::DragonRounded->new;
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 25; $level++) {
my $n_start = 2**($level-1);
my $n_end = 2**$level;
my $min_hypot = 128*$n_end*$n_end;
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + $y*$y;
if ($h < $min_hypot) {
$min_hypot = $h;
$min_pos = "$x,$y";
}
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $prev_min;
print " min r^2 $min_hypot 0b".sprintf('%b',$min_hypot)." at $min_pos factor $factor\n";
}
{
my $factor = $max_hypot / $prev_max;
print " max r^2 $max_hypot 0b".sprintf('%b',$max_hypot)." at $max_pos factor $factor\n";
}
$prev_min = $min_hypot;
$prev_max = $max_hypot;
}
exit 0;
}
{
# points N=2^level
require Math::PlanePath::DragonRounded;
my $path = Math::PlanePath::DragonRounded->new;
for my $n (0 .. 50) {
my ($x,$y) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
my $dx = $x2 - $x;
my $dy = $y2 - $y;
my ($xm,$ym) = $path->n_to_xy($n+.5);
# my $dir = 0;
# for (my $bit = 1; ; ) {
# $dir += ((($n ^ ($n>>1)) & $bit) != 0);
# $bit <<= 1;
# last if $bit > $n;
# # $dir += 1;
# }
# $dir %= 4;
$x += $dx/2;
$y += $dy/2;
print "$n $x,$y $xm,$ym\n";
}
exit 0;
}
{
# reverse checking
require Math::PlanePath::DragonRounded;
my $path = Math::PlanePath::DragonRounded->new;
for my $n (1 .. 50000) {
my ($x,$y) = $path->n_to_xy($n);
my $rev = $path->xy_to_n($x,$y);
if (! defined $rev || $rev != $n) {
if (! defined $rev) { $rev = 'undef'; }
print "$n $x,$y $rev\n";
}
}
exit 0;
}
{
require Image::Base::Text;
my $width = 78;
my $height = 40;
my $ox = $width/2;
my $oy = $height/2;
my $image = Image::Base::Text->new (-width => $width, -height => $height);
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my $store = sub {
my ($x,$y,$c) = @_;
$x *= 2;
$x += $ox;
$y += $oy;
if ($x >= 0 && $y >= 0 && $x < $width && $y < $height) {
my $o = $image->xy($x,$y);
if (defined $o && $o ne ' ' && $o ne $c) {
$c = '.';
}
$image->xy($x,$y,$c);
}
};
for my $n (0 .. 16*256) {
my ($x,$y) = $path->n_to_xy($n);
$y = -$y;
{
$store->($x,$y,'a');
}
{
$store->(-$y,$x,'b');
}
{
$store->(-$x,-$y,'c');
}
{
$store->($y,-$x,'d');
}
}
$image->xy($ox,$oy,'+');
$image->save('/dev/stdout');
exit 0;
}
{
# points N=2^level
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
for my $level (0 .. 50) {
my $n = 2**$level;
my ($x,$y) = $path->n_to_xy($n);
print "$level $n $x,$y\n";
}
exit 0;
}
{
# sx,sy
my $sx = 1;
my $sy = 0;
for my $level (0 .. 50) {
print "$level $sx,$sy\n";
($sx,$sy) = ($sx - $sy,
$sy + $sx);
}
exit 0;
}
Math-PlanePath-113/devel/interpolate.pl 0000644 0001750 0001750 00000015025 12165377675 015707 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::BigRat;
use Math::Polynomial 1;
use Math::Polynomial::Horner;
#use Devel::Comments;
my_interpolate ([ 0, 1, 2, 3, 4 ],
[ 0-0.5, 1-0.5, 4-0.5, 9-0.5, 16-0.5 ]
);
# my_interpolate ([ 1, 2, 3 ],
# [ 2, 9, 21 ]
# );
# my_interpolate ([ reverse 0,1,2,3,4,5 ],
# [ map {$_-16} 0,5,9,12,14,15 ]
# );
exit 0;
# [1,2,3,4],[1+4,12+4+8,35+4+8+8,70+4+8+8+8]
# # step==0
# my_interpolate ([ 0, 1, 2, 3, 4 ],
# [0.5, 0.5, 0.5, 0.5, 0.5 ]);
# # step==1
# # 7 8 9 10
# # 4 5 6
# # 2 3
# # 1
# my_interpolate ([ 0, 1, 2, 3 ],
# [0.5, 1.5, 3.5, 6.5 ]);
# # step==2
# my_interpolate ([ 0, 1, 2, 3 ],
# [0.5, 1.5, 4.5, 9.5 ]);
# # step==3
# my_interpolate ([ 0, 1, 2, 3 ],
# [0.5, 1.5, 5.5, 12.5 ]);
# # step==4
# my_interpolate ([ 0, 1, 2, 3 ],
# [0.5, 1.5, 6.5, 15.5 ]);
# my_interpolate ([ 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
# [ 9, 25, 49, 81, 121, 169, 225, 289, 361 ]
# );
exit 0;
# N = a*s^2 + b*s + c
# = a * (s^2 + b/a s + c/a)
#
# N/a = (s + b/2a)^2 - b^2/4a^2 + c/a
# (s + b/2a)^2 = N/a + b^2/4a^2 - c/a
# s+ b/2a = sqrt(4aN/4a^2 + b^2/4a^2 - 4ac/4a^2)
# = 1/2a * sqrt(4aN + b^2 - 4ac)
#
# -b + sqrt(4aN + b2 - 4ac)
# s = ------------------------
# 2a
#
my_interpolate (
[ 1, 2, 3, 4, 5],
[ map {3*$_} 1,1+4,1+4+9,1+4+9+16,1+4+9+16+25 ],
);
sub bigrat_to_decimal {
my ($rat) = @_;
if (is_pow2($rat->denominator)) {
return $rat->as_float;
} else {
return $rat;
}
}
sub is_pow2 {
my ($n) = @_;
while ($n > 1) {
if ($n & 1) {
return 0;
}
$n >>= 1;
}
return ($n == 1);
}
use constant my_string_config => (variable => '$d',
times => '*',
power => '**',
fold_one => 1,
fold_sign => 1,
fold_sign_swap_end => 1,
power_by_times => 1,
);
# @string_config = (
# # power => '**',
# # fold_one => 1,
# # fold_sign => 1,
# # fold_sign_swap_end => 1,
# # power_by_times => 1,
# );
sub my_interpolate {
my ($xarray, $valarray) = @_;
my $zero = 0;
$zero = Math::BigRat->new(0);
$xarray = [ map {Math::BigRat->new($_)} @$xarray ];
$valarray = [ map {Math::BigRat->new($_)} @$valarray ];
my $p = Math::Polynomial->new($zero);
$p = $p->interpolate($xarray, $valarray);
$p->string_config({ fold_sign => 1,
variable => 'd' });
print "N = $p\n";
$p->string_config({ my_string_config() });
print " = $p\n";
$p->string_config({ my_string_config(),
# convert_coeff => \&bigrat_to_decimal,
});
print " = ",Math::Polynomial::Horner::as_string($p),"\n";
my $a = $p->coeff(2);
return if $a == 0;
my $b = $p->coeff(1);
my $c = $p->coeff(0);
my $x = -$b/(2*$a);
my $y = 4*$a / ((2*$a) ** 2);
my $z = ($b*$b-4*$a*$c) / ((2*$a) ** 2);
print "d = $x + sqrt($y * \$n + $z)\n";
# return;
my $s_to_n = sub {
my ($s) = @_;
return $p->evaluate($s);
};
if (ref $x) {
$x = $x->numify;
$y = $y->numify;
$z = $z->numify;
}
my $n_to_d = sub {
my ($n) = @_;
my $root = $y * $n + $z;
if ($root < 0) {
return 'neg sqrt';
}
return ($x + sqrt($root));
};
# for (my $i = 0; $i < 100; $i += 0.5) {
# printf "%4s d=%s\n", $i, $n_to_d->($i);
# }
exit 0;
}
# {
# package Math::Polynomial;
# sub interpolate {
# my ($this, $xvalues, $yvalues) = @_;
# if (
# !ref($xvalues) || !ref($yvalues) || @{$xvalues} != @{$yvalues}
# ) {
# croak 'usage: $q = $p->interpolate([$x1, $x2, ...], [$y1, $y2, ...])';
# }
# return $this->new if !@{$xvalues};
# my @alpha = @{$yvalues};
# my $result = $this->new($alpha[0]);
# my $aux = $result->monomial(0);
# my $zero = $result->coeff_zero;
# for (my $k=1; $k<=$#alpha; ++$k) {
# for (my $j=$#alpha; $j>=$k; --$j) {
# my $dx = $xvalues->[$j] - $xvalues->[$j-$k];
# croak 'x values not disjoint' if $zero == $dx;
# ### dx: "$dx",ref $dx
# $alpha[$j] = ($alpha[$j] - $alpha[$j-1]) / $dx;
# }
# $aux = $aux->mul_root($xvalues->[$k-1]);
# $result += $aux->mul_const($alpha[$k]);
# ### alpha: join(' ',map{"$_"}@alpha)
# }
# return $result;
# }
# }
{
my $f1 = 1.5;
my $f2 = 4.5;
my $f3 = 9.5;
my $f4 = 16.5;
foreach ($f1, $f2, $f3, $f4) {
$_ = Math::BigRat->new($_);
}
my $a = $f4/2 - $f3 + $f2/2;
my $b = $f4*-5/2 + $f3*6 - $f2*7/2;
my $c = $f4*3 - $f3*8 + $f2*6;
print "$a\n";
print "$b\n";
print "$c\n";
print "$a*\$s*\$s + $b*\$s + $c\n";
exit 0;
}
{
my $subr = sub {
my ($s) = @_;
return 3*$s*$s - 4*$s + 2;
# return 2*$s*$s - 2*$s + 2;
# return $s*$s + .5;
# return $s*$s - $s + 1;
# return $s*($s+1)*.5 + 0.5;
};
my $back = sub {
my ($n) = @_;
return (2 + sqrt(3*$n - 2)) / 3;
# return .5 + sqrt(.5*$n-.75);
# return sqrt ($n - .5);
# return -.5 + sqrt(2*$n - .75);
# return int((sqrt(4*$n-1) - 1) / 2);
};
my $prev = 0;
foreach (1..15) {
my $this = $subr->($_);
printf("%2d %.2f %.2f %.2f\n", $_, $this, $this-$prev,$back->($this));
$prev = $this;
}
for (my $n = 1; $n < 23; $n++) {
printf "%.2f %.2f\n", $n,$back->($n);
}
exit 0;
}
Math-PlanePath-113/devel/gosper-islands-stars.pl 0000644 0001750 0001750 00000002334 11777406713 017436 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.005;
use strict;
use POSIX ();
use Math::PlanePath::GosperIslands;
# uncomment this to run the ### lines
use Smart::Comments;
{
my $path = Math::PlanePath::GosperIslands->new;
my @rows = ((' ' x 64) x 78);
my $level = 3;
my $n_start = 3**$level - 2;
my $n_end = 3**($level+1) - 2 - 1;
foreach my $n ($n_start .. $n_end) {
my ($x, $y) = $path->n_to_xy ($n);
# $x *= 2;
$x+= 16;
$y+= 16;
substr ($rows[$y], $x,1, '*');
}
local $,="\n";
print reverse @rows;
exit 0;
}
Math-PlanePath-113/devel/koch-curve.pl 0000644 0001750 0001750 00000004263 12252723363 015413 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::Util 'sum';
use Math::PlanePath::KochCurve;
{
# A056832 All a(n) = 1 or 2; a(1) = 1; get next 2^k terms by repeating
# first 2^k terms and changing last element so sum of first 2^(k+1) terms
# is odd.
#
# Is lowest non-zero base4 digit(n) 1,3->a(n)=1 2->a(n)=2.
# a(2^k) flips 1<->2 each time for low non-zero flipping 1<->2.
# a(2^k) always flips because odd sum becomes even on duplicating.
#
my @a = (1);
for my $i (1 .. 6) {
push @a, @a;
unless (sum(@a) & 1) {
$a[-1] = 3-$a[-1]; # 2<->1
print "i=$i flip last\n";
}
print @a,"\n";
}
foreach my $i (1 .. 64) {
my $d = base4_lowest_nonzero_digit($i);
if ($d != 2) { $d = 1; }
print $d;
}
print "\n";
exit 0;
}
sub base4_lowest_nonzero_digit {
my ($n) = @_;
while (($n & 3) == 0) {
$n >>= 2;
if ($n == 0) { die "oops, no nonzero digits at all"; }
}
return $n & 3;
}
sub base4_lowest_non3_digit {
my ($n) = @_;
while (($n & 3) == 3) {
$n >>= 2;
}
return $n & 3;
}
{
my $path = Math::PlanePath::KochCurve->new;
foreach my $n (0 .. 16) {
my ($x,$y) = $path->n_to_xy($n);
my $rot = n_to_total_turn($n);
print "$n $x,$y $rot\n";
}
print "\n";
exit 0;
sub n_to_total_turn {
my ($n) = @_;
my $rot = 0;
while ($n) {
if (($n % 4) == 1) {
$rot++;
} elsif (($n % 4) == 2) {
$rot --;
}
$n = int($n/4);
}
return $rot;
}
}
Math-PlanePath-113/devel/dragon-devel.m4 0000644 0001750 0001750 00000003576 12217756131 015627 0 ustar gg gg #!/usr/bin/m4
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
define(`seg_offset_y',`eval((($1 ^ $2) >> 1) & 1)')
define(`seg_offset_x',`seg_offset_y(eval($1+1), eval($2+1))')
define(`seg_to_even',`eval($1 - seg_offset_x($1,$2)),
eval($2 - seg_offset_y($1,$2))');
to even: seg_to_even(0,0)
x: seg_offset_x(0,0)
y: seg_offset_y(0,0)
# # forloop(`y',-8,7,
# # `forloop(`x',-8,7,
# # `seg_offset_y(x,y)')
# # ')
# #
# # forloop(`y',-8,7,
# # `forloop(`x',-8,7,
# # `seg_offset_x(x,y)')
# # ')
#
# isfinal: seg_is_final(0,0)
# to_even: seg_to_even(-2,0)
# vpred: vertex_pred(0,0)
#
# forloop(`y',10,-10,
# `forloop(`x',-10,10,
# `ifelse(vertex_pred(x,y),1, `+', ` ')dnl
# ifelse(seg_pred(vertex_to_seg_east(x,y)), 1, `--', ` ')')
# forloop(`x',-10,10,
# `ifelse(seg_pred(vertex_to_seg_south(x,y)), 1, `| ', ` ')')
# ')
#
# forloop(`y',28,-12,
# `forloop(`x',-32,32,
# `ifelse(x.y,0.z0,`+',vertex_pred(x,y))')
# ')
#
# seg_is_final(xy_div_iplus1(1,1))
# xy_div_iplus1(xy_div_iplus1(4,4))
# xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(4,4)))
# xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(4,4))))
# seg_is_final(xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(xy_div_iplus1(4,4))))))
#
# define(`y',8)
Math-PlanePath-113/devel/factor-rationals.pl 0000644 0001750 0001750 00000017733 12236024533 016616 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::FactorRationals;
# uncomment this to run the ### lines
use Smart::Comments;
{
foreach my $n (1 .. 20) {
print Math::PlanePath::FactorRationals::_pos_to_pn__negabinary($n),",";
}
exit 0;
}
{
# different pos=49 numbers got=69 want=88, and more diff
# N=50 = 5*5*2
my $path = Math::PlanePath::FactorRationals->new;
foreach my $x (1 .. 50) {
my $n = $path->xy_to_n(1,$x);
print "$x $n\n";
}
exit 0;
}
# Return ($good, $prime,$exp, $prime,$exp,...).
# $good is true if a full factorization is found.
# $good is false if cannot factorize because $n is too big or infinite.
#
# If $n==0 or $n==1 then there are no prime factors and the return is
# $good=1 and an empty list of primes.
#
sub INPROGRESS_prime_factors_and_exps {
my ($n) = @_;
### _prime_factors(): $n
unless ($n >= 0) {
return 0;
}
if (_is_infinite($n)) {
return 0;
}
# if ($n <= 0xFFFF_FFFF) {
# return (1, prime_factors($n));
# }
my @ret;
unless ($n % 2) {
my $count = 0;
do {
$count++;
$n /= 2;
} until ($n % 2);
push @ret, 2, $count;
}
# Stop at when prime $p reaches $limit and when no prime factor has been
# found for the last 20 attempted $p. Stopping only after a run of no
# factors found allows big primorials 2*3*5*7*13*... to be divided out.
# If the divisions are making progress reducing $i then continue.
#
# Would like $p and $gap to count primes, not just odd numbers. Perhaps
# a table of small primes. The first gap of 36 odds between primes
# occurs at prime=31469. cf A000230 smallest prime p for gap 2n.
my $limit = 10_000 / (_blog2_estimate($n) || 1);
my $gap = 0;
for (my $p = 3; $gap < 36 || $p <= $limit ; $p += 2) {
if ($n % $p) {
$gap++;
} else {
do {
### prime: $p
$n /= $p;
push @ret, $p;
} until ($n % $p);
if ($n <= 1) {
### all factors found ...
return (1, @ret);
}
# if ($n < 0xFFFF_FFFF) {
# ### remaining factors by XS ...
# return (1, @ret, prime_factors($n));
# }
$gap = 0;
}
}
return 0; # factors too big
}
{
my @primes = (2,3,5,7);
sub _extend_primes {
for (my $p = $primes[-1] + 2; ; $p += 2) {
if (_is_prime($p)) {
push @primes, $p;
return;
}
}
}
sub _is_prime {
my ($n) = @_;
my $limit = int(sqrt($n));
for (my $i = 0; ; $i++) {
if ($i > $#primes) { _extend_primes(); }
my $prime = $primes[$i];
if ($n % $prime == 0) { return 0; }
if ($prime > $limit) { return 1; }
}
}
# $aref is an arrayref of prime exponents, [a,b,c,...]
# Return their product 2**a * 3**b * 5**c * ...
#
sub _factors_join {
my ($aref, $zero) = @_;
### _factors_join(): $aref
my $n = $zero + 1;
for (my $i = 0; $i <= $#$aref; $i++) {
if ($i > $#primes) { _extend_primes(); }
$n *= ($primes[$i] + $zero) ** $aref->[$i];
}
### join: $n
return $n;
}
# Return an arrayref of prime exponents of $n.
# Eg. [a,b,c,...] for $n == 2**a * 3**b * 5**c * ...
sub _factors_split {
my ($n) = @_;
### _factors_split(): $n
my @ret;
for (my $i = 0; $n > 1; $i++) {
if ($i > 6541) {
### stop, primes too big ...
return;
}
if ($i > $#primes) { _extend_primes(); }
my $count = 0;
while ($n % $primes[$i] == 0) {
$n /= $primes[$i];
$count++;
}
push @ret, $count;
}
return \@ret;
}
# ### f: 2*3*3*5*19
# ### f: _factors_split(2*3*3*5*19)
# ### f: _factors_join(_factors_split(2*3*3*5*19),0)
# factor_coding => 'spread'
# "spread"
# if ($self->{'factor_coding'} eq 'spread') {
# # N = 2^e1 * 3^e2 * 5^e3 * 7^e4 * 11^e5 * 13^e6 * 17^e7
# # X = 2^e1 * 3^e3 * 5^e5 * 7^e7, Y = 1
# #
# # X = 2^e1 * 5^e5 e3=0,e7=0
# # Y = 3^e2 * 7^e4
# #
# # X=1,0,1
# # Y=0,0,0
# # 22 = 1,0,0,0,1
# # num = 1,0,1 = 2*5 = 10
# #
# my $xexps = _factors_split($x)
# or return undef; # overflow
# my $yexps = _factors_split($y)
# or return undef; # overflow
# ### $xexps
# ### $yexps
#
# my @nexps;
# my $denpos = -1; # to store first at $nexps[1]
# while (@$xexps || @$yexps) {
# my $xexp = shift @$xexps || 0;
# my $yexp = shift @$yexps || 0;
# ### @nexps
# ### $xexp
# ### $yexp
# push @nexps, $xexp, 0;
# if ($xexp) {
# if ($yexp) {
# ### X,Y common factor ...
# return undef;
# }
# } else {
# ### den store to: "denpos=".($denpos+2)." yexp=$yexp"
# $nexps[$denpos+=2] = $yexp;
# }
# }
# ### @nexps
# return (_factors_join(\@nexps, $x*0*$y));
#
# } els
# if ($self->{'factor_coding'} eq 'spread') {
# # N = 2^e1 * 3^e2 * 5^e3 * 7^e4 * 11^e5 * 13^e6 * 17^e7
# # X = 2^e1 * 3^e3 * 5^e5 * 7^e7, Y = 1
# #
# # X = 2^e1 * 5^e5 e3=0,e7=0
# # Y = 3^e2 * 7^e4
# #
# # 22 = 1,0,0,0,1
# # num = 1,0,1 = 2*5 = 10
# # den = 0
# #
# my $nexps = _factors_split($n)
# or return; # too big
# ### $nexps
# my @dens;
# my (@xexps, @yexps);
# while (@$nexps || @dens) {
# my $exp = shift @$nexps;
# if (@$nexps) {
# push @dens, shift @$nexps;
# }
#
# if ($exp) {
# ### to num: $exp
# push @xexps, $exp;
# push @yexps, 0;
# } else {
# ### zero take den: $dens[0]
# push @xexps, 0;
# push @yexps, shift @dens;
# }
# }
# ### @xexps
# ### @yexps
# return (_factors_join(\@xexps,$zero),
# _factors_join(\@yexps,$zero));
#
# } else
}
{
# reversing binary, max factor=3
# 0 0 0 fac=0
# 1 1 1 fac=1
# 2 2 2 fac=1
# 3 -1 3 fac=3
# 4 4 4 fac=
# 5 -3 5 fac=
# 6 -2 6 fac=3
# 7 3 7 fac=
# 8 8 8 fac=
# 9 -7 9 fac=
# 10 -6 10 fac=
# 11 7 11 fac=
# 12 -4 12 fac=3
# 13 5 13 fac=
# 14 6 14 fac=
# 15 -5 15 fac=3
# 16 16 16 fac=
my $max_fac = 0;
foreach my $n (0 .. 2**20) {
my $pn = Math::PlanePath::FactorRationals::_pos_to_pn__revbinary($n);
my $ninv = Math::PlanePath::FactorRationals::_pn_to_pos__revbinary($pn);
my $fac = $n / abs($pn||1);
if ($fac >= $max_fac) {
$max_fac = $fac;
} else {
$fac = '';
}
print "$n $pn $ninv fac=$fac\n";
die unless $ninv == $n;
}
print "\n";
exit 0;
}
{
# negabinary, max factor approach 5
my %rev;
my $max_fac = 0;
foreach my $n (0 .. 2**20) {
my $power = 1;
my $nega = 0;
for (my $bit = 1; $bit <= $n; $bit <<= 1) {
if ($n & $bit) {
$nega += $power;
}
$power *= -2;
}
my $fnega = Math::PlanePath::FactorRationals::_pos_to_pn__negabinary($n);
my $ninv = Math::PlanePath::FactorRationals::_pn_to_pos__negabinary($nega);
my $fac = -$n / ($nega||1);
if ($fac > $max_fac) {
$max_fac = $fac;
print "$n $nega $fnega $ninv fac=$fac\n";
} else {
$fac = '';
}
$rev{$nega} = $n;
}
print "\n";
exit 0;
foreach my $nega (sort {$a<=>$b} keys %rev) {
my $n = $rev{$nega};
print "$nega $n\n";
}
exit 0;
}
Math-PlanePath-113/devel/complex-minus.pl 0000644 0001750 0001750 00000072367 12203357151 016151 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX;
use List::Util 'min', 'max';
use Math::PlanePath::Base::Digits 'digit_split_lowtohigh';
use Math::PlanePath::ComplexMinus;
use lib 'xt';
use MyOEIS;
# uncomment this to run the ### lines
# use Smart::Comments;
{
# A203181 nxk count endings
# distinct 10,33,108,342,1096,3501,11199,35821
my @distinct;
foreach my $k (2 .. 9) {
print "k=$k\n";
my %counts;
{
my @mats = ([]);
@mats = map {mat_extend($_,$k)} @mats;
@mats = map {mat_extend($_,$k)} @mats;
foreach my $m (@mats) {
$counts{mat_end_to_str($m)}++;
}
}
my $prev_distinct = 0;
for (;;) {
{
my %new_counts;
while (my ($str,$count) = each %counts) {
foreach my $m (mat_extend(str_to_mat($str),$k)) {
$new_counts{mat_end_to_str($m)} += $count;
}
}
%counts = %new_counts;
}
my $distinct = scalar(keys %counts);
print "distinct $distinct\n";
if ($distinct == $prev_distinct) {
push @distinct, $distinct;
last;
}
$prev_distinct = $distinct;
}
print "----------\n";
}
print join(',',@distinct),"\n";
print MyOEIS->grep_for_values_aref(\@distinct);
exit 0;
}
{
my %str_to_mat;
sub str_to_mat {
my ($str) = @_;
return ($str_to_mat{$str}
||= [ map {[split //,$_]} split /;/, $str ]);
}
}
{
# A203181 nxk count
# distinct 10,33,108
my $k = 2;
# my @mats = ([[map {$_%2} 0 .. $k-1]]);
my @mats = ([]);
# @mats = [[1,2],[0,1]];
foreach my $y (0 .. 20) {
### loop for y: $y
@mats = map {mat_extend($_,$k)} @mats;
### mats now: scalar(@mats)
# printmats(@mats);
# foreach my $m (@mats) {
# print join(';',map{join('',@$_)}@$m),"\n";
# }
my %count;
foreach my $m (@mats) {
my $e = mat_end_to_str($m);
$count{$e}++;
}
my $distinct = scalar(keys %count);
printf "yn=%2d count %d (distinct %d)\n", $y+1,scalar(@mats), $distinct;
foreach my $e (sort keys %count) {
print "$e $count{$e}\n";
}
}
exit 0;
}
sub mat_extend {
my ($input_m,$k) = @_;
my $y = scalar(@$input_m);
my @mats = ($input_m);
foreach my $x (0 .. $k-1) {
my @new_mats;
foreach my $m (@mats) {
foreach my $digit (0, 1, 2) {
### consider: $m
### $y
### $x
### $digit
if ($digit == 0) {
next if $y >= 1 && $m->[$y-1]->[$x] == 0; # cannot 0 above
next if $x >= 1 && $m->[$y]->[$x-1] == 0; # cannot 0 left
} elsif ($digit == 1) {
if ($y >= 1 && $m->[$y-1]->[$x] == 0) {
# good, 0 above
} elsif ($x >= 1 && $m->[$y]->[$x-1] == 0) {
# good, 0 left
} else {
# bad
next;
}
} else { # $digit == 2
if ($y >= 2
&& $m->[$y-1]->[$x] == 1 # 1 above, and
&& $m->[$y-2]->[$x] == 0) { # 0 above
# good
} elsif ($x >= 2
&& $m->[$y]->[$x-1] == 1 # 1 above, and
&& $m->[$y]->[$x-2] == 0) { # 0 above
# good
} else {
# bad
next;
}
}
### yes ...
my $new_m = copymat($m);
$new_m->[$y]->[$x] = $digit;
push @new_mats, $new_m;
}
}
@mats = @new_mats;
}
return @mats;
}
sub mat_end_to_str {
my ($m) = @_;
if (@$m >= 2) {
return join('',@{$m->[-2]}) . ';' . join('',@{$m->[-1]});
} else {
return join('',@{$m->[-1]});
}
}
sub printmats {
foreach my $m (@_) {
printaref($m); print "\n";
}
}
sub printaref {
my ($m) = @_;
foreach my $row (@$m) {
print join('',@$row),"\n";
}
}
sub copymat {
my ($m) = @_;
return [ map {[@$_]} @$m ];
}
{
# 0,1 0,1 0,1 0,1 0,1 0,1
# 1,0 1,0 1,0 1,0 1,0 1,0
# 0,1 0,1 0,1 2,1 2,1 0,1
# 1,0 1,2 1,0 0,1 0,2 1,2
# 2,1 2,0 0,1 1,0 1,0 0,1
# A B C D E F G H I J
# 0,1 1,0 1,0 0,1 2,1 2,1 1,2 0,2 2,0 1,2
# 1,0 0,1 2,1 1,2 0,1 0,2 2,0 1,0 0,1 0,1
# --- --- --- --- --- --- --- --- --- ---
# 0,1=B 1,0=A 0,1=E 0,1=J 1,0=A 1,0=H 0,1=I 0,1=B 1,0=A 1,0=A
# 2,1=C 1,2=D 0,2=F 2,0=G H=A I=B 2,1=C 1,2=D
# 2*E E,G F=E H=A I=B J=E
#
# A -> B+C
# B -> A+D B=I
# C -> 2E
# D -> E+G
# E -> A E=F=H=J
# G -> B
#
# 4,6,10,18,30,50,86,146,246,418,710,1202,2038,3458
require Math::Matrix;
# A B C D E F G H I J
my $m = Math::Matrix->new ([0,1,1,0,0,0,0,0,0,0], # A
[1,0,0,1,0,0,0,0,0,0], # B
[0,0,0,0,1,1,0,0,0,0], # C
[0,0,0,0,0,0,1,0,0,1], # D
[1,0,0,0,0,0,0,0,0,0], # E=J
[0,0,0,0,0,0,0,1,0,0], # F
[0,0,0,0,0,0,0,0,1,0], # G
[0,1,1,0,0,0,0,0,0,0], # H=A
[1,0,0,1,0,0,0,0,0,0], # I=B
[1,0,0,0,0,0,0,0,0,0], # J
);
# print "det ",$m->determinant,"\n"; # too slow
=pod
Pari
m = [0,1,1,0,0,0,0,0,0,0; \
1,0,0,1,0,0,0,0,0,0; \
0,0,0,0,1,1,0,0,0,0; \
0,0,0,0,0,0,1,0,0,1; \
1,0,0,0,0,0,0,0,0,0; \
0,0,0,0,0,0,0,1,0,0; \
0,0,0,0,0,0,0,0,1,0; \
0,1,1,0,0,0,0,0,0,0; \
1,0,0,1,0,0,0,0,0,0; \
1,0,0,0,0,0,0,0,0,0 ]
=cut
my $dot = Math::Matrix->new([1,1,1,1,1,1,1,1,1,1,1]);
my $v = Math::Matrix->new([1,0,0,0,0,0,0,0,0,0,0]);
foreach my $i (0 .. 6) {
print "$i\n";
my $p = matrix_pow($m,$i);
my $pv = $v*$p;
print $pv->dot_product($dot),"\n";
matrix_print($pv);
}
# print $v,"\n";
#print $v*($m*$m),"\n";
# print "\nlast\n";
# # 3 2 1 1
# $v = Math::Matrix->new([1,2,2,1,2,1,0,0,0,1]);
# my $pv = $v*$m;
# print $pv->dot_product($dot),"\n";
# print vector_str($pv);
# V*dot = total[i]
# V*M*dot = total[i+1]
# V*M^2*dot = total[i+2]
# V*M^3*dot = total[i+3]
# seek total[i+3] = total[i+2]
# + 0*total[i+1]
# + 2*total[i]
# M^3 = M^2 + 2*I
$v = Math::Matrix->new([1,0,0,0,0,0,0,0,0,0,0]);
my $i = 2;
$dot = $dot->transpose;
my $t0 = ($v * matrix_pow($m,$i)) * $dot;
my $t1 = ($v * matrix_pow($m,$i+1)) * $dot;
my $t2 = ($v * matrix_pow($m,$i+2)) * $dot;
my $t3 = ($v * matrix_pow($m,$i+3)) * $dot;
print "$t0 $t1 $t2 $t3\n";
# my $d = matrix_pow($m,4) - (matrix_pow($m,3) + $m->multiply_scalar(2));
my $d = matrix_pow($m,4) - (matrix_pow($m,3) + $m->multiply_scalar(2));
matrix_print($d); print "\n";
# m^2*dot + 2*dot == m^3*dot
# + $dot->multiply_scalar(2)
{
my $diff = $m*$m*$dot + $dot+$dot - $m*$m*$m*$dot;
print "diff\n"; matrix_print($diff); print "\n";
}
foreach my $exp (-1 .. 5) {
my $diff = matrix_pow($m,$exp+2)
+ matrix_pow($m,$exp)
+ matrix_pow($m,$exp)
- matrix_pow($m,$exp+3) ;
print "diff\n"; matrix_print(($diff*$dot)->transpose); print "\n";
}
# print "m\n"; matrix_print($m); print "\n";
# my $two = $m->multiply_scalar(2);
# print "two\n"; matrix_print($two); print "\n";
# my $three = matrix_pow($m,3);
# print "powthree\n"; matrix_print($three); print "\n";
# my $sum = $three + $two;
# print "sum\n"; matrix_print($sum*$dot); print "\n";
# my $four = matrix_pow($m,4);
# print "four\n"; matrix_print($four*$dot); print "\n";
# my $diff = $four*$dot - $sum*$dot;
# print "four\n"; matrix_print($diff); print "\n";
exit 0;
sub matrix_print {
my ($m) = @_;
my $len = 0;
foreach my $row (@$m) {
foreach my $value (@$row) {
$len = max($len,length($value));
}
}
foreach my $row (@$m) {
foreach my $value (@$row) {
printf " %*s", $len, $value;
}
print "\n";
}
}
# sub vector_str {
# my ($v) = @_;
# my $str = "$v";
# $str =~ s{\.00000 *( |$)}{$1}g;
# return $str;
# }
}
{
require Math::Matrix;
my $m = Math::Matrix->new ([1,0,0],
[0,0,0],
[0,0,0]);
print "det ",$m->determinant,"\n";
my $inv = $m->invert;
print "inverse\n"; matrix_print($inv); print "\n";
my $prod = $m * $inv;
print "prod\n"; matrix_print($prod); print "\n";
my $identity = $m->new_identity(3);
my $wide = $m->concat($identity);
print "wide\n"; matrix_print($wide); print "\n";
my $solve = $wide->solve;
print "solve\n"; matrix_print($solve); print "\n";
exit 0;
}
{
# print A203181 table
require Math::NumSeq::OEIS;
my $seq = Math::NumSeq::OEIS->new(anum=>'A203181');
my @table;
my $len = 0;
DD: for (my $d = 0; ; $d++) {
foreach my $y (0 .. $d) {
my ($i,$value) = $seq->next or last DD;
push @{$table[$y]}, $value;
$len = max($len,length($value));
}
}
$len++;
print "len=$len\n";
$len = 15;
foreach my $y (0 .. $#table) {
my $aref = $table[$y];
foreach my $x (0 .. $#$aref) {
last if $x > 3;
my $value = $aref->[$x];
printf "%*d", $len, $value;
}
print "\n";
}
exit 0;
}
{
require Math::Matrix;
my $m = Math::Matrix->new ([1,2,3],
[0,0,0],
[0,0,0],
);
print matrix_pow($m,0);
exit 0;
}
# m^(2k) = (m^2)^k
# m^(2k+1) = (m^2)^k*m
sub matrix_pow {
my ($m, $exp, $swap) = @_;
if ($swap) { # when called through "**" operator overload.
die "Cannot raise scalar to matrix power";
}
if ($exp != int($exp)) {
die "Cannot raise matrix to non-integer power";
}
if ($exp == 0) {
my $size = @$m;
if ($size != scalar(@{$m->[0]})) {
# non-square matrix, no inverse and so no identity
return undef;
}
return $m->new_identity($m->size);
}
if ($exp < 0) {
$m = $m->invert;
if (! defined $m) { return undef; }
$exp = -$exp;
}
unless ($exp / 2 < $exp) {
die "Cannot raise matrix to infinite power";
}
# Result is $low * ($m ** $exp).
# When $exp odd, ($m ** ($e+1)) = ($m**$e)*$m, so $low*=$m then $e even.
# When $exp even, ($m ** (2*$k)) = ($m*$m) ** $k, so $m*=$m.
# $low is undef if it's the identity matrix and so not needed yet.
# If $exp is a power-of-2 then $low is never needed, just $m squared up.
# Use $exp%2 rather than $exp&1 since that allows NV powers (NV can be a
# 53-bit integer whereas UV might be only 32-bits).
my $low;
while ($exp > 1) {
if ($exp % 2) {
if (defined $low) { $low *= $m; }
else { $low = $m; }
$exp -= 1;
}
$m *= $m;
$exp /= 2;
}
if (defined $low) { $m *= $low; }
return $m;
}
{
# neighbours across 2^k blocks
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
my @dir8_to_dx = (1, 1, 0,-1, -1, -1, 0, 1);
my @dir8_to_dy = (0, 1, 1, 1, 0, -1, -1,-1);
my $path = Math::PlanePath::ComplexMinus->new;
my @values;
my $prev_count = 0;
foreach my $k (0 .. 13) {
my $pow = 2**$k;
my $count = 0;
foreach my $n (2 .. $pow-1) {
my ($x,$y) = $path->n_to_xy($n);
# foreach my $i (0 .. $#dir4_to_dx) {
foreach my $i (0, 2) {
my $n2 = $path->xy_to_n($x+$dir4_to_dx[$i],
$y+$dir4_to_dy[$i]);
if (defined $n2 && $n2 >= $pow) { # num boundary
$count++;
last;
}
# if (defined $n2 && $n2 >= $pow && $n2 < 2*$pow) {
# $count++;
# last;
# }
}
}
my $value = ($count - $prev_count)/1;
# my $value = $count/2;
# my $value = $count;
printf "%2d %4d %10b\n", $k, $value, $value;
push @values, $value;
$prev_count = $count;
}
shift @values;
shift @values;
print join(',',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
{
# counting all 4 directions, is boundary length
# 2 * A003476 a(n) = a(n-1) + 2a(n-3).
# 1, 2, 3, 5, 9, 15, 25, 43, 73, 123, 209, 355,
# A203175 nX2 arrays 1, 1, 2, 4, 6, 10, 18, 30, 50, 86, 146, 246, 418, 710,
# 1 immediately preceded by 0 to the left or above
# 0 not immediately preceded by a 0
# 2 immediately preceded by 0 1 to the left or above
# 4,6,10,18,30,50,86,146,246,418,710,1202,2038,3458
#
# 30 = 18+2*6
#
# A052537 2*A or 2*B or 2*C
# n=4 a(4)=4
# 0,1 0,1 0,1 0,1
# 1,0 1,0 1,0 1,0
# 0,1 0,1 2,1 2,1
# 1,0 1,2 0,1 0,2
# [2] [2] [2] [1] = 7
#
# n=5 a(4)=6
# 0,1 0,1 0,1 0,1 0,1 0,1
# 1,0 1,0 1,0 1,0 1,0 1,0
# 0,1 0,1 0,1 2,1 2,1 0,1
# 1,0 1,2 1,0 0,1 0,2 1,2
# 2,1 2,0 0,1 1,0 1,0 0,1
# [2] [?] [2] [2] [2] [2] = 10
#
# 0,1 -> 1,0 later 1,2
# 0,2 -> 1,0
# 1,0 -> 0,1 2,1
# 1,2 -> 0,1 2,0
# 2,0 ->
# 2,1 -> 0,1 0,2
# +---+---+
# | 0 1 | boundary[2^1] = 6
# +---+---+
# +---+---+
# | 2 3 |
# +---+ +---+
# | 0 1 |
# +---+---+
# (2n-1 0 2n ) (a)
# (n^2-2n+2 0 (n-1)^2 ) (b)
# (0 1 0 ) (c)
#
# inverse [ (n^2 - 2*n + 1)/(-n^2 - 1) -2*n/(-n^2 - 1) 0]
# [ 0 0 1]
# [(-n^2 + 2*n - 2)/(-n^2 - 1) (2*n - 1)/(-n^2 - 1) 0]
#
# c[k] = b[k-1]
# a[k] = (2n-1)a[k-1] + 2n*c[k-1]
#
# m = [2*n-1,0,2*n; n^2-2*n+2,0,(n-1)^2; 0,1,0]
# v = [n;n^2+1-n;1] so m*v transforms to new A,B,C
# m^-1*v = [n ; 1; 1-n]
# t=[0,0,0; 0,0,0; 1,1,1]
# f=[0,1,0; 0,0,1; 1,0,0]
# f*t=[0,0,0; 1,1,1; 0,0,0]
# f^2*t=[1,1,1; 0,0,0; 0,0,0]
# s=(t + f*t*m + f^2*t*m^2)
# s*abc = l210
# s*m*abc = r*l210
# s*m*abc = r*s*abc
# s*m = r*s
# r = s*m*s^-1
# r=s*m*s^-1 = [ 2*n-1, n^2+1 - 2*n, n^2+1]
# [1 0 0]
# [0 1 0]
#
# (1 0 2) ( 0 1 0) r=1 initial (1) prev (1)
# (1 0 0) ( 0 0 1) (1) (1)
# (0 1 0) ( 1/2 -1/2 0) (1) (0)
# m=[1,0,2;1,0,0;0,1,0]
#
# (3 0 4) (-1/5 4/5 0) r=2 initial (2) prev -2+4*3 = 2
# (2 0 1) ( 0 0 1) (3) = 1
# (0 1 0) ( 2/5 -3/5 0) (1) = -1
# m=[3,0,4;2,0,1;0,1,0]
# 20 21 22 23 24
# 15 16 17 18 19
# 10 11 12 13 14
# 5 6 7 8 9
# 0 1 2 3 4
# 0 -> 4
# 5 -> 12
# 25 -> (5+8+5)*2 = 36
# l2 = 2*(norm # top
# + r*(norm-1) # steps
# + norm) # side
# = 2*(norm + r*norm - r + norm)
# = 2*(2*norm + r*norm - r)
# = 2*((r+2)*norm - r)
# = 2*((r+2)*norm - r-2 +2))
# = 2*((r+2)*norm - (r+2) +2))
# = 2*(r+2)*(norm-1) + 4
my $r = 2;
my $norm = $r*$r+1;
sub boundary_by_recurrence {
my ($k) = @_;
# my $l2 = 2*$r**3 + 4*$r**2 + 4;
my $l2 = 2*($norm-1)*($r+2) + 4;
my $l1 = 2*$norm + 2;
my $l0 = 4;
foreach (1 .. $k) {
($l2,$l1,$l0) = ((2*$r-1) * $l2
+ ($norm - 2*$r) * $l1
+ $norm * $l0,
$l2, $l1);
# ($l2,$l1,$l0) = ((2*$r-1)*$l2
# + ($r**2+1 - 2*$r)*$l1
# + ($r**2+1)*$l0,
#
# $l2, $l1);
}
return $l0;
}
sub abc_by_pow {
my ($k) = @_;
# my $a = 2*2;
# my $b = 1*2;
# my $c = -1*2;
# my $a = $r*2;
# my $b = ($norm-$r)*2;
# my $c = 1*2;
# my $a = 2 * $r / ($r*$r+1);
# my $b = 2 * ($r*$r+1 - $r) / ($r*$r+1);
# my $c = 2 * 1;
my $a = 2*$r;
my $b = 2;
my $c = 2*(1-$r);
foreach (1 .. $k) {
($a,$b,$c) = ((2*$r-1)*$a + 0 + 2*$r*$c,
($r*$r-2*$r+2)*$a + 0 + ($r-1)*($r-1)*$c,
0 + $b);
}
return ($a,$b,$c);
}
sub boundary_by_pow {
my ($k) = @_;
my ($a,$b,$c) = abc_by_pow($k);
return 2*($a+$b+$c);
}
my @values;
my $path = Math::PlanePath::ComplexMinus->new (realpart => $r);
my $prev_len = 1;
my $prev_ratio = 1;
foreach my $k (1 .. 30) {
my $pow = $norm**$k;
my $len = 0; #path_boundary_length($path,$pow);
my $len_by_pow = boundary_by_pow($k);
my $len_by_rec = boundary_by_recurrence($k);
my $ratio = $pow / $len_by_pow;
my $f = 2* log($len_by_pow / $prev_len) / log($norm);
printf "%2d %s %s %s %.6f\n", $k, $len, $len_by_pow, $len_by_rec, $f;
my ($a,$b,$c) = abc_by_pow($k);
push @values, $a;
$prev_len = $len_by_pow;
$prev_ratio = $ratio;
}
print "seek ",join(', ',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
BEGIN {
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_boundary_length {
my ($path, $n_below) = @_;
### $n_below
my $boundary = 0;
my %seen;
my @pending_x = (0);
my @pending_y = (0);
while (@pending_x) {
my $x = pop @pending_x;
my $y = pop @pending_y;
next if $seen{$x}{$y};
foreach my $i (0 .. $#dir4_to_dx) {
my $ox = $x + $dir4_to_dx[$i];
my $oy = $y + $dir4_to_dy[$i];
### consider: "$x,$y to $ox,$oy"
my $n = $path->xy_to_n($ox,$oy);
if ($n >= $n_below) {
### outside ...
$boundary++;
} else {
### inside ...
push @pending_x, $ox;
push @pending_y, $oy;
}
}
$seen{$x}{$y} = 1;
}
return $boundary;
}
}
{
# min/max rectangle
#
# repeat at dx,dy
require Math::BaseCnv;
my $xmin = 0;
my $xmax = 0;
my $ymin = 0;
my $ymax = 0;
my $dx = 1;
my $dy = 0;
my $realpart = 2;
my $norm = $realpart*$realpart + 1;
printf "level xmin xmax xdiff | ymin ymax ydiff\n";
for (0 .. 22) {
my $xminR = Math::BaseCnv::cnv($xmin,10,$norm);
my $yminR = Math::BaseCnv::cnv($ymin,10,$norm);
my $xmaxR = Math::BaseCnv::cnv($xmax,10,$norm);
my $ymaxR = Math::BaseCnv::cnv($ymax,10,$norm);
my $xdiff = $xmax - $xmin;
my $ydiff = $ymax - $ymin;
my $xdiffR = Math::BaseCnv::cnv($xdiff,10,$norm);
my $ydiffR = Math::BaseCnv::cnv($ydiff,10,$norm);
printf "%2d %11s %11s =%11s | %11s %11s =%11s\n",
$_,
$xminR,$xmaxR,$xdiffR,
$yminR,$ymaxR,$ydiffR;
$xmax = max ($xmax, $xmax + $dx*($norm-1));
$ymax = max ($ymax, $ymax + $dy*($norm-1));
$xmin = min ($xmin, $xmin + $dx*($norm-1));
$ymin = min ($ymin, $ymin + $dy*($norm-1));
### assert: $xmin <= 0
### assert: $ymin <= 0
### assert: $xmax >= 0
### assert: $ymax >= 0
# multiply i-r, ie. (dx,dy) = (dx + i*dy)*(i-$realpart)
$dy = -$dy;
($dx,$dy) = ($dy - $realpart*$dx,
$dx + $realpart*$dy);
}
# print 3*$xmin/$len+.001," / 3\n";
# print 6*$xmax/$len+.001," / 6\n";
# print 3*$ymin/$len+.001," / 3\n";
# print 3*$ymax/$len+.001," / 3\n";
exit 0;
sub to_bin {
my ($n) = @_;
return ($n < 0 ? '-' : '') . sprintf('%b', abs($n));
}
}
{
# min/max hypot for level
$|=1;
my $realpart = 2;
my $norm = $realpart**2 + 1;
my $path = Math::PlanePath::ComplexMinus->new (realpart => $realpart);
my $prev_min = 1;
my $prev_max = 1;
for (my $level = 1; $level < 25; $level++) {
my $n_start = $norm**($level-1);
my $n_end = $norm**$level;
my $min_hypot = POSIX::DBL_MAX();
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + $y*$y;
if ($h < $min_hypot) {
$min_hypot = $h;
$min_pos = "$x,$y";
}
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
# print "$min_hypot,";
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $prev_min;
print " min r^2 $min_hypot 0b".sprintf('%b',$min_hypot)." at $min_pos factor $factor\n";
print " cf formula ", 2**($level-7), "\n";
}
# {
# my $factor = $max_hypot / $prev_max;
# print " max r^2 $max_hypot 0b".sprintf('%b',$max_hypot)." at $max_pos factor $factor\n";
# }
$prev_min = $min_hypot;
$prev_max = $max_hypot;
}
exit 0;
}
{
# covered inner rect
# depends on which coord extended first
require Math::BaseCnv;
$|=1;
my $realpart = 1;
my $norm = $realpart**2 + 1;
my $path = Math::PlanePath::ComplexMinus->new (realpart => $realpart);
my %seen;
my $xmin = 0;
my $xmax = 0;
my $ymin = 0;
my $ymax = 0;
for (my $level = 1; $level < 25; $level++) {
my $n_start = $norm**($level-1);
my $n_end = $norm**$level - 1;
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
$seen{"$x,$y"} = 1;
$xmin = min ($xmin, $x);
$xmax = max ($xmax, $x);
$ymin = min ($ymin, $y);
$ymax = max ($ymax, $y);
}
my $x1 = 0;
my $y1 = 0;
my $x2 = 0;
my $y2 = 0;
for (;;) {
my $more = 0;
{
my $x = $x1-1;
my $good = 1;
foreach my $y ($y1 .. $y2) {
if (! $seen{"$x,$y"}) {
$good = 0;
last;
}
}
if ($good) {
$more = 1;
$x1 = $x;
}
}
{
my $x = $x2+1;
my $good = 1;
foreach my $y ($y1 .. $y2) {
if (! $seen{"$x,$y"}) {
$good = 0;
last;
}
}
if ($good) {
$more = 1;
$x2 = $x;
}
}
{
my $y = $y1-1;
my $good = 1;
foreach my $x ($x1 .. $x2) {
if (! $seen{"$x,$y"}) {
$good = 0;
last;
}
}
if ($good) {
$more = 1;
$y1 = $y;
}
}
{
my $y = $y2+1;
my $good = 1;
foreach my $x ($x1 .. $x2) {
if (! $seen{"$x,$y"}) {
$good = 0;
last;
}
}
if ($good) {
$more = 1;
$y2 = $y;
}
}
last if ! $more;
}
printf "%2d %10s %10s %10s %10s\n",
$level,
Math::BaseCnv::cnv($x1,10,2),
Math::BaseCnv::cnv($x2,10,2),
Math::BaseCnv::cnv($y1,10,2),
Math::BaseCnv::cnv($y2,10,2);
}
exit 0;
}
{
# n=2^k bits
require Math::BaseCnv;
my $path = Math::PlanePath::ComplexMinus->new;
foreach my $i (0 .. 16) {
my $n = 2**$i;
my ($x,$y) = $path->n_to_xy($n);
my $x2 = Math::BaseCnv::cnv($x,10,2);
my $y2 = Math::BaseCnv::cnv($y,10,2);
printf "%#7X %12s %12s\n", $n, $x2, $y2;
}
print "\n";
# X axis bits
require Math::BaseCnv;
foreach my $x (0 .. 400) {
my $n = $path->xy_to_n($x,0);
my $w = int(log($n||1)/log(2)) + 2;
my $n2 = Math::BaseCnv::cnv($n,10,2);
print "x=$x n=$n = $n2\n";
for (my $bit = 1; $bit <= $n; $bit <<= 1) {
if ($n & $bit) {
my ($x,$y) = $path->n_to_xy($bit);
my $x2 = Math::BaseCnv::cnv($x,10,2);
my $y2 = Math::BaseCnv::cnv($y,10,2);
printf " %#*X %*s %*s\n", $w, $bit, $w, $x2, $w, $y2;
}
}
}
print "\n";
exit 0;
}
{
# X axis generating
# hex 1 any X=0x1 or -1
# 2 never
# C bits 4,8 together X=0x2 or -2
my @ns = (0, 1, 0xC, 0xD);
my @xseen;
foreach my $pos (1 .. 5) {
push @ns, map {16*$_+0, 16*$_+1, 16*$_+0xC, 16*$_+0xD} @ns;
}
my $path = Math::PlanePath::ComplexMinus->new;
require Set::IntSpan::Fast;
my $set = Set::IntSpan::Fast->new;
foreach my $n (@ns) {
my ($x,$y) = $path->n_to_xy($n);
$y == 0 or die "n=$n x=$x y=$y";
$set->add($x);
}
print "ok $#ns\n";
print "x span ",$set->as_string,"\n";
print "x card ",$set->cardinality,"\n";
exit 0;
}
{
# n=2^k bits
require Math::BaseCnv;
my $path = Math::PlanePath::ComplexMinus->new;
foreach my $i (0 .. 20) {
my $n = 2**$i;
my ($x,$y) = $path->n_to_xy($n);
my $x2 = Math::BaseCnv::cnv($x,10,2);
my $y2 = Math::BaseCnv::cnv($y,10,2);
printf "%6X %20s %11s\n", $n, $x2, $y2;
}
print "\n";
exit 0;
}
{
# X axis
require Math::BaseCnv;
require Math::NumSeq::PlanePathN;
my $seq = Math::NumSeq::PlanePathN->new (planepath=> 'ComplexMinus',
line_type => 'X_axis');
foreach my $i (0 .. 150) {
my ($i,$value) = $seq->next;
my $v2 = Math::BaseCnv::cnv($value,10,2);
printf "%4d %20s\n", $value, $v2;
}
print "\n";
exit 0;
}
{
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath=> 'ComplexMinus',
delta_type => 'dX');
foreach my $i (0 .. 50) {
my ($i,$value) = $seq->next;
print "$value,";
}
print "\n";
exit 0;
}
{
# max Dir4
require Math::BaseCnv;
print 4-atan2(2,1)/atan2(1,1)/2,"\n";
require Math::NumSeq::PlanePathDelta;
my $realpart = 3;
my $radix = $realpart*$realpart + 1;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => "ComplexPlus,realpart=$realpart",
delta_type => 'Dir4');
my $dx_seq = Math::NumSeq::PlanePathDelta->new (planepath => "ComplexPlus,realpart=$realpart",
delta_type => 'dX');
my $dy_seq = Math::NumSeq::PlanePathDelta->new (planepath => "ComplexPlus,realpart=$realpart",
delta_type => 'dY');
my $max = 0;
for (1 .. 1000000) {
my ($i, $value) = $seq->next;
# foreach my $k (1 .. 1000000) {
# my $i = $radix ** (4*$k+3) - 1;
# my $value = $seq->ith($i);
if ($value > $max) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dy && $dx/$dy;
printf "%d %s %.5f %s %s %.3f\n", $i, $ri, $value, $rdx,$rdy, $f;
$max = $value;
}
}
exit 0;
}
{
# innermost points coverage
require Math::BaseCnv;
foreach my $realpart (1 .. 20) {
my $norm = $realpart**2 + 1;
my $path = Math::PlanePath::ComplexMinus->new (realpart => $realpart);
my $n_max = 0;
my $show = sub {
my ($x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
print "$x,$y n=$n\n";
if ($n > $n_max) {
$n_max = $n;
}
};
$show->(1,0);
$show->(1,1);
$show->(0,1);
$show->(-1,1);
$show->(-1,0);
$show->(-1,-1);
$show->(0,-1);
$show->(1,-1);
my $n_max_base = to_base($n_max,$norm);
my $n_max_log = log($n_max)/log($norm);
print "n_max $n_max $n_max_base $n_max_log\n";
print "\n";
}
exit 0;
sub to_base {
my ($n, $radix) = @_;
my $ret = '';
do {
my $digit = $n % $radix;
$ret = "[$digit]$ret";
} while ($n = int($n/$radix));
return $ret;
}
}
{
require Math::PlanePath::ComplexPlus;
require Math::BigInt;
my $realpart = 10;
my $norm = $realpart*$realpart + 1;
### $norm
my $path = Math::PlanePath::ComplexPlus->new (realpart=>$realpart);
my $prev_dist = 1;
print sqrt($norm),"\n";
foreach my $level (1 .. 10) {
my $n = Math::BigInt->new($norm) ** $level - 1;
my ($x,$y) = $path->n_to_xy($n);
my $radians = atan2($y,$x);
my $degrees = $radians / 3.141592 * 180;
my $dist = sqrt($x*$x+$y*$y);
my $f = $dist / $prev_dist;
printf "%2d %.2f %.4f %.2f\n",
$level, $dist, $f, $degrees;
$prev_dist = $dist;
}
exit 0;
}
{
require Math::PlanePath::ComplexPlus;
my $path = Math::PlanePath::ComplexPlus->new (realpart=>2);
foreach my $i (0 .. 10) {
{
my $x = $i;
my $y = 1;
my $n = $path->xy_to_n($x,$y);
if (! defined $n) { $n = 'undef'; }
print "xy_to_n($x,$y) = $n\n";
}
}
foreach my $i (0 .. 10) {
{
my $n = $i;
my ($x,$y) = $path->n_to_xy($n);
print "n_to_xy($n) = $x,$y\n";
}
}
exit 0;
}
{
my $count = 0;
my $realpart = 5;
my $norm = $realpart*$realpart+1;
foreach my $x (-200 .. 200) {
foreach my $y (-200 .. 200) {
my $new_x = $x;
my $neg_y = $x - $y*$realpart;
my $digit = $neg_y % $norm;
$new_x -= $digit;
$neg_y -= $digit;
next unless ($new_x*$realpart+$y)/$norm == $x;
next unless -$neg_y/$norm == $y;
print "$x,$y digit=$digit\n";
$count++;
}
}
print "count $count\n";
exit 0;
}
Math-PlanePath-113/devel/cfrac-digits.pl 0000644 0001750 0001750 00000014004 12155466372 015704 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX 'floor';
use List::Util 'min', 'max';
use Math::PlanePath::CfracDigits;
use Math::PlanePath::Base::Digits
'round_down_pow';
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::KochCurve;
*_digit_join_hightolow = \&Math::PlanePath::KochCurve::_digit_join_hightolow;
# 121313322
{
require Math::PlanePath::CfracDigits;
my $path = Math::PlanePath::CfracDigits->new;
foreach my $n (0 .. 120) {
my ($x,$y) = $path->n_to_xy($n);
print "$x,";
}
print "\n";
print "\n";
foreach my $n (0 .. 120) {
my ($x,$y) = $path->n_to_xy($n);
print "$y,";
}
print "\n";
print "\n";
foreach my $n (0 .. 120) {
my ($x,$y) = $path->n_to_xy($n);
print "$x/$y, ";
}
print "\n";
print "\n";
exit 0;
}
{
require Math::PlanePath::CfracDigits;
require Number::Fraction;
my $path = Math::PlanePath::CfracDigits->new (radix => 1);
my $rat = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $nf = Number::Fraction->new(1,7);
$nf = 1 / (4 + 1 / (2 + Number::Fraction->new(1,7)));
print "$nf\n";
my $x = $nf->{num};
my $y = $nf->{den};
my $n = $path->xy_to_n($x,$y);
printf "%5d %17b\n", $n, $n;
$n = $rat->xy_to_n($y-$x,$x);
printf "%5d %17b\n", $n, $n;
exit 0;
}
{
# +1 at low end to turn 1111 into 10000
require Math::PlanePath::CfracDigits;
my $rat = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my $cf = Math::PlanePath::CfracDigits->new (radix => 1);
for (my $n = $rat->n_start; $n < 200; $n++) {
my ($cx,$cy) = $cf->n_to_xy($n);
# my ($rx,$ry) = $rat->n_to_xy($n);
my $rn = $rat->xy_to_n($cy,$cx);
printf "%d,%d %b %b\n",
$cx,$cy, $n, $rn-1;
}
exit 0;
}
{
# Fibonacci F[k]/F[k+1]
require Math::NumSeq::Fibonacci;
my $seq = Math::NumSeq::Fibonacci->new;
my $radix = 3;
my $path = Math::PlanePath::CfracDigits->new (radix => $radix);
for (my $i = 1; $i < 20; $i++) {
my $x = $seq->ith($i);
my $y = $seq->ith($i+1);
my $log = Math::PlanePath::CfracDigits::_log_phi_estimate($y);
my $n = $path->xy_to_n($x,$y);
# {
# my @digits = ($radix+1) x ($i-2);
# my $carry = 0;
# foreach my $digit (@digits) { # low to high
# if ($carry = (($digit += $carry) >= $radix)) { # modify array contents
# $digit -= $radix;
# }
# }
# if ($carry) {
# push @digits, 1;
# }
# print join(',',@digits),"\n";
# }
my @digits = ($radix+1) x ($i-2);
my $d = Math::PlanePath::CfracDigits::_digit_join_1toR_destructive(\@digits,$radix+1,0);
my $pow = ($radix+1)**$i;
my ($nlo,$nhi) = $path->rect_to_n_range(0,0, $x,$y);
print "$n $log $nhi $d $pow\n";
}
exit 0;
}
{
# range vs GcdRationals
my $radix = 2;
require Math::PlanePath::CfracDigits;
require Math::PlanePath::GcdRationals;
my $cf = Math::PlanePath::CfracDigits->new (radix => $radix);
my $gc = Math::PlanePath::GcdRationals->new;
foreach my $y (2 .. 1000) {
my ($cf_nlo,$cf_nhi) = $cf->rect_to_n_range(0,0, 1,$y);
my ($gc_nlo,$gc_nhi) = $gc->rect_to_n_range(0,0, $y,$y);
my $flag = '';
if ($cf_nhi > $gc_nhi) {
$flag = "*****";
}
print "$y $cf_nhi $gc_nhi$flag\n";
}
exit 0;
}
{
# maximum N
require Math::PlanePath::CfracDigits;
my $radix = 6;
my $path = Math::PlanePath::CfracDigits->new (radix => $radix);
foreach my $y (2 .. 1000) {
my $nmax = -1;
my $xmax;
foreach my $x (1 .. $y-1) {
my $n = $path->xy_to_n($x,$y) // next;
my $len = $n; # length_1toR($n);
if ($len > $nmax) {
$nmax = $len;
$xmax = $x;
# print " $xmax $nmax ",groups_string($n),"\n";
}
}
my ($nlo,$nhi) = $path->rect_to_n_range(0,0,1,$y);
my $groups = groups_string($nmax);
my $ysquared = ($radix+1) ** (_fib_log($y) - 1.5);
# my $ysquared = ($radix+1) ** (log2($y)*2);
# my $ysquared = int($y ** (5/2));
my $yfactor = sprintf '%.2f', $ysquared / ($nmax||1);
my $flag = '';
if ($ysquared < $nmax) {
$flag = "*****";
}
print "$y x=$xmax n=$nmax $ysquared$flag $yfactor $groups\n";
my $log = Math::PlanePath::CfracDigits::_log_phi_estimate($y);
$flag = '';
if ($nhi < $nmax) {
$flag = "*****";
}
print " nhi=$nhi$flag log=$log\n";
}
exit 0;
sub groups_string {
my ($n) = @_;
my @groups = Math::PlanePath::CfracDigits::_n_to_quotients($n,$radix);
return join(',',reverse @groups);
}
sub length_1toR {
my ($n) = @_;
my @digits = Math::PlanePath::CfracDigits::_digit_split_1toR_lowtohigh($n,$radix);
return scalar(@digits);
}
sub log2 {
my ($x) = @_;
return int(log($x)/log(2));
}
sub _fib_log {
my ($x) = @_;
### _fib_log(): $x
my $f0 = ($x * 0);
my $f1 = $f0 + 1;
my $count = 0;
while ($x > $f0) {
$count++;
($f0,$f1) = ($f1,$f0+$f1);
}
return $count;
}
}
{
# minimum N in each row is at X=1
require Math::PlanePath::CfracDigits;
my $path = Math::PlanePath::CfracDigits->new;
foreach my $y (2 .. 1000) {
my $nmin = 1e308;
my $xmin;
foreach my $x (1 .. $y-1) {
my $n = $path->xy_to_n($x,$y) // next;
if ($n < $nmin) {
$nmin = $n;
$xmin = $x;
}
}
print "$y $xmin $nmin\n";
}
exit 0;
}
Math-PlanePath-113/devel/pythagorean.pl 0000644 0001750 0001750 00000060147 12252501660 015663 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::Util 'min', 'max';
use Math::Libm 'hypot';
use Math::PlanePath::PythagoreanTree;
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_join_lowtohigh',
'digit_split_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments;
{
# powers
foreach my $k (0 .. 41) {
print 3**$k,"\n";
}
exit 0;
}
{
# repeated "U" or "M1" on initial P=2,Q=1
require Math::BaseCnv;
my $path = Math::PlanePath::PythagoreanTree->new
(
# tree_type => 'UAD',
tree_type => 'FB',
coordinates => 'PQ',
);
foreach my $depth (0 .. 5) {
my $n = $path->tree_depth_to_n($depth);
my ($x,$y) = $path->n_to_xy($n);
print "depth=$depth N=$n P=$x / Q=$y\n";
}
exit 0;
}
{
# X,Y list
# PQ UAD
# N=1 2 / 1
#
# N=2 3 / 2 5,12
# N=3 5 / 2 21,20
# N=4 4 / 1 15,8
#
# N=5 4 / 3
# N=6 8 / 3
# N=7 7 / 2
# N=8 8 / 5
# N=9 12 / 5
# N=10 9 / 2
# N=11 7 / 4
# N=12 9 / 4
# N=13 6 / 1
# PQ FB
# N=1 2,1
#
# N=2 3,2
# N=3 4,1
# N=4 4,3
#
# N=5 5,4
# N=6 6,1
# N=7 6,5
# N=8 5,2
# N=9 8,3
# N=10 8,5
# N=11 7,6
# N=12 8,1
# N=13 8,7
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new
(
# tree_type => 'UMT',
tree_type => 'UAD',
# tree_type => 'FB',
coordinates => 'AB',
# coordinates => 'PQ', # P>Q one odd other even
);
my $n = $path->n_start;
foreach my $level (0 .. 5) {
foreach (1 .. 3**$level) {
my ($x,$y) = $path->n_to_xy($n);
# $x -= $y;
my $flag = '';
if ($x <= $y) {
$flag = ' ***';
}
print "N=$n $x,$y$flag\n";
$n++;
}
print "\n";
}
exit 0;
}
{
# TMU parent/child
foreach my $n (1 .. 40) {
if (n_is_row_start($n)) { print "\n"; }
my $n_str = n_to_pythagstr($n);
my ($p,$q) = tmu_n_to_pq($n);
my @pq_children = tmu_pq_children($p,$q);
my ($p1,$q1,$p2,$q2,$p3,$q3) = @pq_children;
print "$n = $n_str $p,$q children $p1,$q1 $p2,$q2 $p3,$q3\n";
while (@pq_children) {
my $child_p = shift @pq_children;
my $child_q = shift @pq_children;
my ($parent_p,$parent_q) = tmu_pq_parent($child_p,$child_q);
if ($parent_p != $p || $parent_q != $q) {
print "oops\n";
}
}
}
exit 0;
sub tmu_pq_children {
my ($p,$q) = @_;
return ($p+3*$q, 2*$q, # T
2*$p, $p-$q, # M2 (2p, p-q)
2*$p-$q, $p); # "U" = (2p-q, p)
}
sub tmu_pq_parent {
my ($p,$q) = @_;
if ($p > 2*$q) {
if ($p % 2) {
# T 1 3 p -> p+3q p > 2q, p odd, q even
# 0 2 q -> 2q det=2
# inverse 1 -3/2
# 0 1/2
$q /= 2;
$p -= 3*$q;
} else {
# M2 2 0 p -> 2p p > 2q, p even, q odd
# 1 -1 q -> p-q det=-2
# inverse -1 0 / -2 = 1/2 0
# -1 2 1/2 -1
$p /= 2;
$q = $p - $q;
}
} else {
# U 2 -1 p -> 2p-q 2q > p > q small p
# 1 0 q -> p det=1
# inverse 0 1 = 0 -1
# -1 2 1 -2
($p,$q) = ($q, 2*$q-$p);
}
return ($p,$q);
}
}
{
# 1^2 = 1 3^2 = 9 = 1 mod 4
# A^2 + B^2 = C^2
# 1 0 1
# 0 1 1
# A = 1 mod 4, B = 0 mod 4
# even 3mod4, any 1mod4
exit 0;
}
{
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'UMT',
coordinates => 'PQ');
$path->xy_to_n(4,5);
exit 0;
}
{
# UAD to TMU
my $uad = Math::PlanePath::PythagoreanTree->new (tree_type => 'UAD',
coordinates => 'PQ');
foreach my $n (1 .. 40) {
if (n_is_row_start($n)) { print "\n"; }
my ($p,$q) = $uad->n_to_xy($n);
my $umt_n = umt_pq_to_n($p,$q);
my $umt_n_str = n_to_pythagstr($umt_n);
my $n_str = n_to_pythagstr($n);
print "$n = $n_str $p,$q UMT=$n $umt_n_str\n";
}
exit 0;
sub umt_pq_to_n {
my ($p,$q) = @_;
my @ndigits;
while ($p > 2) {
if ($p > 2*$q) {
if ($p % 2) {
$q /= 2; # T
$p -= 3*$q;
push @ndigits, 1;
} else {
$p /= 2; # M2
$q = $p - $q;
push @ndigits, 2;
}
} else {
($p,$q) = ($q, 2*$q-$p); # U
push @ndigits, 0;
}
}
my $zero = $p*0*$q;
return ((3+$zero)**scalar(@ndigits) + 1)/2 # tree_depth_to_n()
+ digit_join_lowtohigh(\@ndigits,3,$zero); # digits within this depth
}
}
{
# U = 2,-1,1,0
# A = 2,1, 1,0
# D = 1,2, 0,1
# M1 = 1,1, 0,2
# M2 = 2,0, 1,-1
# M3 = 2,0, 1,1
# p+2q = unchanged
# p+q = odd
# 2p or 2q = even
# 2a+b>2c+d
# ap+b>cp+d
#
# ap+b(p-1) > cp+d(p-1)
# (c-1)p+b(p-1) > cp+d(p-1)
# cp-p+b(p-1) > cp+d(p-1)
# -p+b(p-1) > d(p-1)
# b(p-1) > d(p-1)+p
# b > d+p/(p-1)
# b > d+1
# D A U
# 1,2,0,1 2,-1,1,0 2,1,1,0
#
# U 2 -1 p -> 2p-q 2q > p > q small p
# 1 0 q -> p det=1
#
# A 2 1 p -> 2p+q 3q > p > 2q mid p
# 1 0 q -> p det=-1
#
# D 1 2 p -> p+2q p > 3q big p
# 0 1 q -> q det=1
# M1 M2 M3
# 1,1,0,2 2,0,1,-1 2,0,1,1
#
# M1 1 1 p -> p+q p > 2q, p odd, q even
# 0 2 q -> 2q det=2
#
# M2 2 0 p -> 2p p > 2q, p even, q odd
# 1 -1 q -> p-q det=-2
#
# M3 2 0 p -> 2p 2q > p, small p, p even, q odd
# 1 1 q -> p+q det=2
# U M2
# 1,3,0,2 2,-1,1,0 2,0,1,-1
#
#
# T 1 3 p -> p+3q p > 2q, p odd, q even
# 0 2 q -> 2q det=2
#
# M2 2 0 p -> 2p p > 2q, p even, q odd
# 1 -1 q -> p-q det=-2
#
# U 2 1 p -> 2p-q 2q > p > q small p
# 1 0 q -> p det=-1
my $uad = Math::PlanePath::PythagoreanTree->new (tree_type => 'UAD',
coordinates => 'PQ');
my $fb = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB',
coordinates => 'PQ');
my $len = 0;
foreach my $n (1 .. 40) {
if (n_is_row_start($n)) { print "\n"; }
my ($p,$q) = tmu_n_to_pq($n);
my $uad_n = n_to_pythagstr($uad->xy_to_n($p,$q));
my $fb_n = n_to_pythagstr($fb->xy_to_n($p,$q));
my $n_str = n_to_pythagstr($n);
print "$n = $n_str $p,$q UAD N=$uad_n FB N=$fb_n\n";
}
exit 0;
sub n_is_row_start {
my ($n) = @_;
my ($pow, $exp) = round_down_pow (2*$n-1, 3);
return ($n == ($pow+1)/2);
}
sub tmu_n_to_pq {
my ($n) = @_;
my $p = 2;
my $q = 1;
foreach my $digit (n_to_pythag_digits_lowtohigh($n)) {
if ($digit == 0) {
$p += 3*$q; # T
$q *= 2;
} elsif ($digit == 1) {
$q = $p-$q; # (2p, p-q) M2
$p *= 2;
} else {
($p,$q) = (2*$p-$q, $p); # "U" = (2p-q, p)
}
}
return ($p,$q);
}
sub n_to_pythagstr {
my ($n) = @_;
if (! defined $n) { return '[undef]' }
if ($n < 1) { return "($n)"; }
my @digits = n_to_pythag_digits_lowtohigh($n);
return '1.'.join('',reverse @digits);
}
# ($pow+1)/2 = row start
# pow = 3^exp
# N - rowstart + 3^exp = N - (pow+1)/2 + pow
# = N - pow/2 - 1/2 + pow
# = N + pow/2 - 1/2
# = N + (pow-1)/2
sub n_to_pythag_digits_lowtohigh {
my ($n) = @_;
my ($pow, $exp) = round_down_pow (2*$n-1, 3);
my @digits = digit_split_lowtohigh($n + ($pow-1)/2,3);
pop @digits; # high 1
return @digits;
}
}
{
# P,Q tables
my $path = Math::PlanePath::PythagoreanTree->new(coordinates => 'PQ');
foreach my $n ($path->n_start .. $path->tree_depth_to_n_end(2)) {
my ($p,$q) = $path->n_to_xy($n);
print "$p,";
}
print "\n";
foreach my $n ($path->n_start .. $path->tree_depth_to_n_end(2)) {
my ($p,$q) = $path->n_to_xy($n);
print "$q,";
}
print "\n";
exit 0;
}
{
require Devel::TimeThis;
require Math::PlanePath::FractionsTree;
my $path = Math::PlanePath::FractionsTree->new
(
# tree_type => 'FB',
# tree_type => 'UAD',
# coordinates => 'BC',
# coordinates => 'PQ', # P>Q one odd other even
);
{
my $t = Devel::TimeThis->new('xy_is_visited');
foreach my $x (0 .. 200) {
foreach my $y (0 .. 200) {
$path->xy_is_visited($x,$y);
}
}
}
{
my $t = Devel::TimeThis->new('xy_to_n');
foreach my $x (0 .. 200) {
foreach my $y (0 .. 200) {
$path->xy_to_n($x,$y);
}
}
}
exit 0;
}
{
# numbers in a grid
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new
(
# tree_type => 'FB',
# tree_type => 'UAD',
# coordinates => 'AB',
coordinates => 'MC',
);
my @rows;
foreach my $n (1 .. 100000) {
my ($orig_x,$orig_y) = $path->n_to_xy($n);
my $x = $orig_x / 2;
my $y = $orig_y / 4;
next if $y > 25;
next if $x > 80;
print "$n $orig_x,$orig_y\n";
$rows[$y] ||= ' 'x80;
substr($rows[$y],$x,length($n)) = $n;
}
for (my $y = $#rows; $y >= 0; $y--) {
$rows[$y] ||= '';
$rows[$y] =~ s/ +$//;
print $rows[$y],"\n";
}
exit 0;
}
{
# repeated "M1" as p,q matrix
# P+(2^k-1)*Q, 2^k*Q
# applied to P=2,Q=1
# 2+(2^k-1) = 2^k + 1, 2^k
require Math::Matrix;
my $u = Math::Matrix->new ([1,1],
[0,2]);
my $m = $u;
foreach (1 .. 5) {
print "$m\n";
$m *= $u;
}
exit 0;
}
{
# repeated "U" as p,q matrix
require Math::Matrix;
my $u = Math::Matrix->new ([2,-1],
[1,0]);
my $m = $u;
foreach (1 .. 5) {
print "$m\n";
$m *= $u;
}
exit 0;
}
{
# high bit 1 in ternary
require Math::BaseCnv;
for (my $n = 1; $n < 65536; $n *= 2) {
my $n3 = Math::BaseCnv::cnv($n,10,3);
my $n2 = Math::BaseCnv::cnv($n,10,2);
printf "$n $n2 $n3\n";
}
exit 0;
}
{
# Fibonacci's method for primitive triples.
# odd numbers 1,3,5,7,...,k being n terms n=(k+1)/2 with k square
# sum 1+3+5+7+...+k = n^2 the gnomons around a square
# a^2 = k = 2n-1
# b^2 = sum 1+3+5+...+k-2 = (n-1)^2
# c^2 = sum 1+3+5+...+k-2+k = n^2
# so a^2+b^2 = c^2
# (n-1)^2 + 2n-1 = n^2-2n+1 + 2n-1 = n^2
#
# i=3
# o=2i-1=5
# k=o^2 = 5^2 = 25
# n=(k+1)/2 = (25+1)/2=13
# a=o = 5
# b = n-1 = 12
#
# i=4
# o=2i-1=7
# k=o^2 = 7^2 = 49
# n=(k+1)/2 = (49+1)/2=25
# a=o = 7
# b = n-1 = 24
sub fibonacci_ab {
my ($i) = @_;
$i = 2*$i+1; # odd integer
my $k = $i**2; # a^2 = k = odd square
my $n = ($k+1)/2;
return ($i, # a=sqrt(k)
$n-1); # b=n-1
}
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new (tree_type => 'FB');
foreach my $i (1 .. 30) {
my ($a,$b) = fibonacci_ab($i);
my $c = sqrt($a*$a+$b*$b);
# my $n = $path->tree_depth_to_n($i-1);
# my ($pa,$pb) = $path->n_to_xy($n);
# print "$i $a,$b,$c $n $pa,$pb\n";
my $n = $path->xy_to_n($a,$b);
my $depth = $path->tree_n_to_depth($n);
print "$i $a,$b,$c $n depth=$depth\n";
}
exit 0;
}
{
# P,Q by rows
require Math::BaseCnv;
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ');
my $fb = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ',
tree_type => 'FB');
my $level = 8;
my $prev_depth = -1;
for (my $n = $path->n_start; ; $n++) {
my $depth = $path->tree_n_to_depth($n);
last if $depth > 4;
if ($depth != $prev_depth) {
print "\n";
$prev_depth = $depth;
}
my ($x,$y) = $path->n_to_xy($n);
printf " %2d/%-2d", $x,$y;
my ($fx,$fy) = $fb->n_to_xy($n);
printf " %2d/%-2d", $fx,$fy;
my $fn = $path->xy_to_n($fx,$fy);
print " ",n_to_treedigits_str($n);
print " ",n_to_treedigits_str($fn);
print "\n";
}
exit 0;
}
{
require Math::BigInt::Lite;
my $x = Math::BigInt::Lite->new(3);
my $y = Math::BigInt::Lite->new(4);
Math::PlanePath::PythagoreanTree::_ab_to_pq($x,$y);
exit 0;
}
{
require Math::BigInt::Lite;
my $x = Math::BigInt::Lite->new(3);
my $low = $x & 1;
### $low
exit 0;
}
{
require Math::BigInt::Lite;
my $x = Math::BigInt::Lite->new(3);
my $y = Math::BigInt::Lite->new(4);
### $x
### $y
my ($a, $b) = ($x,$y);
### _ab_to_pq(): "A=$a, B=$b"
unless ($a >= 3 && $b >= 4 && ($a % 2) && !($b % 2)) {
### don't have A odd, B even ...
return;
}
# This used to be $c=hypot($a,$b) and check $c==int($c), but libm hypot()
# on Darwin 8.11.0 is somehow a couple of bits off being an integer, for
# example hypot(57,176)==185 but a couple of bits out so $c!=int($c).
# Would have thought hypot() ought to be exact on integer inputs and a
# perfect square sum :-(. Check for a perfect square by multiplying back
# instead.
#
my $c;
{
my $csquared = $a*$a + $b*$b;
$c = int(sqrt($csquared));
### $csquared
### $c
unless ($c*$c == $csquared) {
return;
}
}
exit 0;
}
{
require Math::BigInt::Lite;
my $x = Math::BigInt::Lite->new(3);
my $y = Math::BigInt::Lite->new(4);
### $x
### $y
# my $csquared = $x*$x + $y*$y;
# my $c = int(sqrt($csquared));
# ### $c
# my $mod = $x%2;
# $mod = $y%2;
my $eq = ($x*$x == $y*$y);
### $eq
# my $x = 3;
# my $y = 4;
# $x = Math::BigInt::Lite->new($x);
# $y = Math::BigInt::Lite->new($y);
# $mod = $x%2;
# $mod = $y%2;
unless ($x >= 3 && $y >= 4 && ($x % 2) && !($y % 2)) {
### don't have A odd, B even ...
die;
}
# {
# my $eq = ($c*$c == $csquared);
# ### $eq
# }
exit 0;
}
{
# P,Q continued fraction quotients
require Math::BaseCnv;
require Math::ContinuedFraction;
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ');
my $level = 8;
foreach my $n (1 .. 3**$level) {
my ($x,$y) = $path->n_to_xy($n);
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $cfrac_str = $cfrac->to_ascii;
# my $nbits = Math::BaseCnv::cnv($n,10,3);
my $nbits = n_to_treedigits_str($n);
printf "%3d %7s %2d/%-2d %s\n", $n, $nbits, $x,$y, $cfrac_str;
}
exit 0;
sub n_to_treedigits_str {
my ($n) = @_;
return "~".join('',n_to_treedigits($n));
}
sub n_to_treedigits {
my ($n) = @_;
my ($len, $level) = round_down_pow (2*$n-1, 3);
my @digits = digit_split_lowtohigh ($n - ($len+1)/2, 3);
$#digits = $level-1; # pad to $level with undefs
foreach (@digits) { $_ ||= 0 }
return @digits;
}
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ');
require Math::BigInt;
# my ($n_lo,$n_hi) = $path->rect_to_n_range (1000,0, 1500,200);
my ($n_lo,$n_hi) = $path->rect_to_n_range (Math::BigInt->new(1000),0, 1500,200);
### $n_hi
### n_hi: "$n_hi"
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
# my $path = Math::PlanePath::PythagoreanTree->new
# (
# # tree_type => 'FB',
# tree_type => 'UAD',
# coordinates => 'AB',
# );
# my ($x,$y) = $path->n_to_xy(1121);
# # exit 0;
foreach my $k (1 .. 10) {
print 3 * 2**$k + 1,"\n";
print 2**($k+2)+1,"\n";
}
sub minpos {
my $min = $_[0];
my $pos = 0;
foreach my $i (1 .. $#_) {
if ($_[$i] < $min) {
$min = $_[$i];
$pos = 1;
}
}
return $pos;
}
require Math::BaseCnv;
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new
(
# tree_type => 'UAD',
tree_type => 'FB',
# coordinates => 'AB',
coordinates => 'PQ',
);
my $n = 1;
foreach my $level (1 .. 100) {
my @x;
my @y;
print "level $level base n=$n\n";
my $base = $n;
my ($min_x, $min_y) = $path->n_to_xy($n);
my $min_x_n = $n;
my $min_y_n = $n;
foreach my $rem (0 .. 3**($level-1)-1) {
my ($x,$y) = $path->n_to_xy($n);
if ($x < $min_x) {
$min_x = $x;
$min_x_n = $n;
}
if ($y < $min_y) {
$min_y = $y;
$min_y_n = $n;
}
$n++;
}
my $min_x_rem = $min_x_n - $base;
my $min_y_rem = $min_y_n - $base;
my $min_x_rem_t = sprintf '%0*s', $level-1, Math::BaseCnv::cnv($min_x_rem,10,3);
my $min_y_rem_t = sprintf '%0*s', $level-1, Math::BaseCnv::cnv($min_y_rem,10,3);
print " minx=$min_x at n=$min_x_n rem=$min_x_rem [$min_x_rem_t]\n";
print " miny=$min_y at n=$min_y_n rem=$min_y_rem [$min_y_rem_t]\n";
local $,='..';
print $path->rect_to_n_range(0,0, $min_x,$min_y),"\n";
}
exit 0;
}
{
my $path = Math::PlanePath::PythagoreanTree->new
(tree_type => 'UAD');
foreach my $level (1 .. 20) {
# my $n = 3 ** $level;
my $n = (3 ** $level - 1) / 2;
my ($x,$y) = $path->n_to_xy($n);
print "$x, $y\n";
}
exit 0;
}
{
# low zeros p=q+1 q=2^k
my $p = 2;
my $q = 1;
### initial
### $p
### $q
foreach (1 .. 3) {
($p,$q) = (2*$p-$q, $p);
### $p
### $q
}
($p,$q) = (2*$p+$q, $p);
### mid
### $p
### $q
foreach (1 .. 3) {
($p,$q) = (2*$p-$q, $p);
### $p
### $q
}
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my (undef, $n_hi) = $path->rect_to_n_range(0,0, 1000,1000);
### $n_hi
my @count;
foreach my $n (1 .. $n_hi) {
my ($x,$y) = $path->n_to_xy($n);
my $z = hypot($x,$y);
$count[$z]++;
}
my $total = 0;
foreach my $i (1 .. $#count) {
if ($count[$i]) {
$total += $count[$i];
my $ratio = $total/$i;
print "$i $total $ratio\n";
}
}
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my $n = 1;
foreach my $x (0 .. 10000) {
foreach my $y (0 .. $x) {
my $n = $path->xy_to_n($x,$y);
next unless defined $n;
my ($nx,$ny) = $path->n_to_xy($n);
if ($nx != $x || $ny != $y) {
### $x
### $y
### $n
### $nx
### $ny
}
}
}
exit 0;
}
{
my ($q,$p) = (21,46);
print "$q / $p\n";
{
my $a = $p*$p - $q*$q;
my $b = 2*$p*$q;
my $c = $p*$p + $q*$q;
print "$a $b $c\n";
{
require Math::BaseCnv;
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my $n = 1;
for ( ; $n < 3**11; $n++) {
my ($x,$y) = $path->n_to_xy($n);
if (($x == $a && $y == $b)
|| ($x == $b && $y == $a)) {
print "n=$n\n";
last;
}
}
my $level = 1;
$n -= 2;
while ($n >= 3**$level) {
$n -= 3**$level;
$level++;
}
my $remt = sprintf "%0*s", $level, Math::BaseCnv::cnv($n,10,3);
print "level $level remainder $n [$remt]\n";
}
}
my $power = 1;
my $rem = 0;
foreach (1..8) {
my $digit;
if ($q & 1) {
$p /= 2;
if ($q > $p) {
$q = $q - $p;
$digit = 2;
} else {
$q = $p - $q;
$digit = 1;
}
} else {
$q /= 2;
$p -= $q;
$digit = 0;
}
print "$digit $q / $p\n";
$rem += $power * $digit;
$power *= 3;
last if $q == 1 && $p == 2;
}
print "digits $rem\n";
exit 0;
}
{
# my ($a, $b, $c) = (39, 80, 89);
my ($a, $b, $c) = (36,77,85);
if (($a ^ $c) & 1) {
($a,$b) = ($b,$a);
}
print "$a $b $c\n";
my $p = sqrt (($a+$c)/2);
my $q = $b/(2*$p);
print "$p $q\n";
$a = $p*$p - $q*$q;
$b = 2*$p*$q;
$c = $p*$p + $q*$q;
print "$a $b $c\n";
exit 0;
}
{
require Math::Matrix;
my $f = Math::Matrix->new ([2,0],
[1,1]);
my $g = Math::Matrix->new ([-1,1],
[0,2]);
my $h = Math::Matrix->new ([1,1],
[0,2]);
my $fi = $f->invert;
print $fi,"\n";
my $gi = $g->invert;
print $gi,"\n";
my $hi = $h->invert;
print $hi,"\n";
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my $n = 1;
foreach my $i (1 .. 100) {
my ($x,$y) = $path->n_to_xy($n);
# print 2**($i),"\n";
# print 2*2**$i*(2**$i-1),"\n";
my $z = hypot($x,$y);
printf "%3d %4d,%4d,%4d\n", $n, $x, $y, $z;
$n += 3**$i;
}
exit 0;
}
{
sub round_down_pow_3 {
my ($n) = @_;
my $p = 3 ** (int(log($n)/log(3)));
return (3*$p <= $n ? 3*$p
: $p > $n ? $p/3
: $p);
}
require Math::BaseCnv;
# base = (range-1)/2
# range = 2*base + 1
#
# newbase = ((2b+1)/3 - 1) / 2
# = (2b+1-3)/3 / 2
# = (2b-2)/2/3
# = (b-1)/3
#
# deltarem = b-(b-1)/3
# = (3b-b+1)/3
# = (2b+1)/3
#
foreach my $n (1 .. 32) {
my $h = 2*($n-1)+1;
my $level = int(log($h)/log(3));
$level--;
my $range = 3**$level;
my $base = ($range - 1)/2 + 1;
my $rem = $n - $base;
if ($rem < 0) {
$rem += $range/3;
$level--;
$range /= 3;
}
if ($rem >= $range) {
$rem -= $range;
$level++;
$range *= 3;
}
my $remt = Math::BaseCnv::cnv($rem,10,3);
$remt = sprintf ("%0*s", $level, $remt);
print "$n $h $level $range base=$base $rem $remt\n";
}
exit 0;
}
{
my $sum = 0;
foreach my $k (0 .. 10) {
$sum += 3**$k;
my $f = (3**($k+1) - 1) / 2;
print "$k $sum $f\n";
}
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my $x_limit = 500;
my @max_n;
foreach my $n (0 .. 500000) {
my ($x,$y) = $path->n_to_xy($n);
if ($x <= $x_limit) {
$max_n[$x] = max($max_n[$x] || $n, $n);
}
}
foreach my $x (0 .. $x_limit) {
if ($max_n[$x]) {
print "$x $max_n[$x]\n";
}
}
exit 0;
}
{
require Math::PlanePath::PythagoreanTree;
my $path = Math::PlanePath::PythagoreanTree->new;
my $x_limit = 500;
my @max_n;
foreach my $n (0 .. 500000) {
my ($x,$y) = $path->n_to_xy($n);
if ($x <= $x_limit) {
$max_n[$x] = max($max_n[$x] || $n, $n);
}
}
foreach my $x (0 .. $x_limit) {
if ($max_n[$x]) {
print "$x $max_n[$x]\n";
}
}
exit 0;
}
{
require Math::Matrix;
my $u = Math::Matrix->new ([1,2,2],
[-2,-1,-2],
[2,2,3]);
my $a = Math::Matrix->new ([1,2,2],
[2,1,2],
[2,2,3]);
my $d = Math::Matrix->new ([-1,-2,-2],
[2,1,2],
[2,2,3]);
my $ui = $u->invert;
print $ui;
exit 0;
}
{
my (@x) = 3;
my (@y) = 4;
my (@z) = 5;
for (1..3) {
for my $i (0 .. $#x) {
print "$x[$i], $y[$i], $z[$i] ",sqrt($x[$i]**2+$y[$i]**2),"\n";
}
print "\n";
my @new_x;
my @new_y;
my @new_z;
for my $i (0 .. $#x) {
my $x = $x[$i];
my $y = $y[$i];
my $z = $z[$i];
push @new_x, $x - 2*$y + 2*$z;
push @new_y, 2*$x - $y + 2*$z;
push @new_z, 2*$x - 2*$y + 3*$z;
push @new_x, $x + 2*$y + 2*$z;
push @new_y, 2*$x + $y + 2*$z;
push @new_z, 2*$x + 2*$y + 3*$z;
push @new_x, - $x + 2*$y + 2*$z;
push @new_y, -2*$x + $y + 2*$z;
push @new_z, -2*$x + 2*$y + 3*$z;
}
@x = @new_x;
@y = @new_y;
@z = @new_z;
}
exit 0;
}
Math-PlanePath-113/devel/staircase-alternating.pl 0000644 0001750 0001750 00000001750 11717623507 017633 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::StaircaseAlternating;
# uncomment this to run the ### lines
use Smart::Comments;
{
my $path = Math::PlanePath::StaircaseAlternating->new (end_type => 'square');
my @nlohi = $path->rect_to_n_range (0,2, 2,4);
### @nlohi
exit 0;
}
Math-PlanePath-113/devel/alternate-paper.pl 0000644 0001750 0001750 00000020176 12203071435 016422 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::Trig 'pi';
use Math::PlanePath::Base::Digits 'digit_split_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments;
{
# total turn
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
my $total = 0;
my $bits_total = 0;
my @values;
for (my $n = 1; $n <= 32; $n++) {
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $n4 = Math::BaseCnv::cnv($n,10,4);
printf "%10s %10s %2d %2d\n", $n2, $n4, $total, $bits_total;
# print "$total,";
push @values, $total;
$bits_total = total_turn_by_bits($n);
my $turn = path_n_turn ($path, $n);
if ($turn == 1) { # left
$total++;
} elsif ($turn == 0) { # right
$total--;
} else {
die;
}
}
use lib 'xt'; require MyOEIS;
print join(',',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
use Math::PlanePath;
use Math::PlanePath::GrayCode;
sub total_turn_by_bits {
my ($n) = @_;
my $bits = [ digit_split_lowtohigh($n,2) ];
my $rev = 0;
my $total = 0;
for (my $pos = $#$bits; $pos >= 0; $pos--) { # high bit to low bit
my $bit = $bits->[$pos];
if ($rev) {
if ($bit) {
} else {
if ($pos & 1) {
$total--;
} else {
$total++;
}
$rev = 0;
}
} else {
if ($bit) {
if ($pos & 1) {
$total--;
} else {
$total++;
}
$rev = 1;
} else {
}
}
}
return $total;
}
exit 0;
}
{
require Math::PlanePath::AlternatePaper;
require Math::PlanePath::AlternatePaperMidpoint;
my $paper = Math::PlanePath::AlternatePaper->new (arms => 8);
my $midpoint = Math::PlanePath::AlternatePaperMidpoint->new (arms => 8);
foreach my $n (0 .. 7) {
my ($x1,$y1) = $paper->n_to_xy($n);
my ($x2,$y2) = $paper->n_to_xy($n+8);
my ($mx,$my) = $midpoint->n_to_xy($n);
my $x = $x1+$x2; # midpoint*2
my $y = $y1+$y2;
($x,$y) = (($x+$y-1)/2,
($x-$y-1)/2); # rotate -45 and shift
print "$n $x,$y $mx,$my\n";
}
exit 0;
}
{
# grid X,Y offset
require Math::PlanePath::AlternatePaperMidpoint;
my $path = Math::PlanePath::AlternatePaperMidpoint->new (arms => 8);
my %dxdy_to_digit;
my %seen;
for (my $n = 0; $n < 4**4; $n++) {
my $digit = $n % 4;
foreach my $arm (0 .. 7) {
my ($x,$y) = $path->n_to_xy(8*$n+$arm);
my $nb = int($n/4);
my ($xb,$yb) = $path->n_to_xy(8*$nb+$arm);
$xb *= 2;
$yb *= 2;
my $dx = $xb - $x;
my $dy = $yb - $y;
my $dxdy = "$dx,$dy";
my $show = "${dxdy}[$digit]";
$seen{$x}{$y} = $show;
if ($dxdy eq '0,0') {
}
$dxdy_to_digit{$dxdy} = $digit;
}
}
foreach my $y (reverse -45 .. 45) {
foreach my $x (-5 .. 5) {
printf " %9s", $seen{$x}{$y}//'e'
}
print "\n";
}
### %dxdy_to_digit
exit 0;
}
{
# sum/sqrt(n) goes below pi/4
print "pi/4 ",pi/4,"\n";
require Math::PlanePath::AlternatePaper;
my $path = Math::PlanePath::AlternatePaper->new;
my $min = 999;
for my $n (1 .. 102400) {
my ($x,$y) = $path->n_to_xy($n);
my $sum = $x+$y;
my $frac = $sum/sqrt($n);
# printf "%10s %.4f\n", "$n,$x,$y", $frac;
$min = min($min,$frac);
}
print "min $min\n";
exit 0;
}
{
# repeat points
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
for my $nn (0 .. 1024) {
my ($x,$y) = $path->n_to_xy($nn);
next unless $y == 18;
my ($n,$m) = $path->xy_to_n_list($x,$y);
next unless ($n == $nn) && $m;
my $diff = $m - $n;
my $xor = $m ^ $n;
my $n4 = Math::BaseCnv::cnv($n,10,4);
my $m4 = Math::BaseCnv::cnv($m,10,4);
my $diff4 = Math::BaseCnv::cnv($diff,10,4);
my $xor4 = Math::BaseCnv::cnv($xor,10,4);
printf "%10s %6s %6s %6s,%-6s\n",
"$n,$x,$y", $n4, $m4, $diff4, $diff4;
}
exit 0;
}
{
# dY
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
for (my $n = 1; $n <= 64; $n += 2) {
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $n4 = Math::BaseCnv::cnv($n,10,4);
my $dy = path_n_dy ($path, $n);
my $nhalf = $n>>1;
my $grs_half = GRS($nhalf);
my $calc_dy = $grs_half * (($nhalf&1) ? -1 : 1);
my $diff = ($calc_dy == $dy ? '' : ' ****');
my $grs = GRS($n);
printf "%10s %10s %2d %2d %2d%s\n", $n2, $n4,
$dy,
$grs,
$calc_dy,$diff;
}
exit 0;
sub GRS {
my ($n) = @_;
return (count_1_bits($n&($n>>1)) & 1 ? -1 : 1);
}
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
}
{
# base4 X,Y axes and diagonal
# diagonal base4 all twos
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
for my $x (0 .. 40) {
my $y;
$y = 0;
$y = $x;
my $n = $path->xy_to_n($x,$y);
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $n4 = Math::BaseCnv::cnv($n,10,4);
printf "%14s %10s %4d %d,%d\n",
$n2, $n4, $n,$x,$y;
}
exit 0;
}
{
# dX
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
for (my $n = 0; $n <= 64; $n += 2) {
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $n4 = Math::BaseCnv::cnv($n,10,4);
my ($dx,$dy) = $path->n_to_dxdy($n);
my $grs = GRS($n);
my $calc_dx = 0;
my $diff = ($calc_dx == $dx ? '' : ' ****');
printf "%10s %10s %2d %2d %2d%s\n", $n2, $n4,
$dx,
$grs,
$calc_dx,$diff;
}
exit 0;
}
{
# plain rev
# 0 0 0 -90
# 1 +90 1 0
# 2 0 2 +90
# 3 -90 3 0
#
# dX ends even so plain, count 11 bits mod 2
# dY ends odd so rev,
# dX,dY
require Math::PlanePath::AlternatePaper;
require Math::BaseCnv;
my $path = Math::PlanePath::AlternatePaper->new;
for (my $n = 0; $n <= 128; $n += 2) {
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
my $dx = $next_x - $x;
my $dy = - path_n_dy ($path,$n ^ 0xFFFF);
my $n2 = Math::BaseCnv::cnv($n,10,2);
my $n4 = Math::BaseCnv::cnv($n,10,4);
printf "%10s %10s %2d,%2d\n", $n2, $n4, $dx,$dy;
}
exit 0;
sub path_n_dx {
my ($path,$n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
return $next_x - $x;
}
sub path_n_dy {
my ($path,$n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
return $next_y - $y;
}
}
# return 1 for left, 0 for right
sub path_n_turn {
my ($path, $n) = @_;
my $prev_dir = path_n_dir ($path, $n-1);
my $dir = path_n_dir ($path, $n);
my $turn = ($dir - $prev_dir) % 4;
if ($turn == 1) { return 1; }
if ($turn == 3) { return 0; }
die "Oops, unrecognised turn";
}
# return 0,1,2,3
sub path_n_dir {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n);
my ($next_x,$next_y) = $path->n_to_xy($n+1);
return dxdy_to_dir ($next_x - $x,
$next_y - $y);
}
# return 0,1,2,3, with Y reckoned increasing upwards
sub dxdy_to_dir {
my ($dx, $dy) = @_;
if ($dx > 0) { return 0; } # east
if ($dx < 0) { return 2; } # west
if ($dy > 0) { return 1; } # north
if ($dy < 0) { return 3; } # south
}
Math-PlanePath-113/devel/square-spiral.pl 0000644 0001750 0001750 00000002263 11722575776 016151 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::PlanePath::SquareSpiral;
# uncomment this to run the ### lines
#use Smart::Comments;
{
require Math::Prime::XS;
my @primes = (0,
Math::Prime::XS::sieve_primes (1000));
my $path = Math::PlanePath::SquareSpiral->new;
foreach my $y (reverse -4 .. 4) {
foreach my $x (-4 .. 4) {
my $n = $path->xy_to_n($x,$y);
my $p = $primes[$n] // '';
printf " %4d", $p;
}
print "\n";
}
exit 0;
}
Math-PlanePath-113/devel/gosper-side.pl 0000644 0001750 0001750 00000004360 11606533603 015562 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use Math::Libm 'M_PI', 'hypot';
{
# minimum hypot beyond N=3^level
#
require Math::PlanePath::GosperSide;
require Math::BaseCnv;
my $path = Math::PlanePath::GosperSide->new;
my $prev_min_hypot = 1;
foreach my $level (0 .. 40) {
my $n_level = 3**$level;
my $min_n = $n_level;
my ($x,$y) = $path->n_to_xy($min_n);
my $min_hypot = hypot($x,sqrt(3)*$y);
foreach my $n ($n_level .. 1.0001*$n_level) {
my ($x,$y) = $path->n_to_xy($n);
my $h = hypot($x,sqrt(3)*$y);
if ($h < $min_hypot) {
$min_n = $n;
$min_hypot = $h;
}
}
my $min_n3 = Math::BaseCnv::cnv($min_n, 10, 3);
my $factor = $min_hypot / $prev_min_hypot;
printf "%2d %8d %15s %9.2f %7.4f %7.4g\n",
$level, $min_n, "[$min_n3]", $min_hypot, $factor, $factor-sqrt(7);
$prev_min_hypot = $min_hypot;
}
exit 0;
}
{
# growth of 3^level hypot
#
require Math::PlanePath::GosperSide;
my $path = Math::PlanePath::GosperSide->new;
my $prev_angle = 0;
my $prev_dist = 0;
foreach my $level (0 .. 20) {
my ($x,$y) = $path->n_to_xy(3**$level);
$y *= sqrt(3);
my $angle = atan2($y,$x);
$angle *= 180/M_PI();
if ($angle < 0) { $angle += 360; }
my $delta_angle = $angle - $prev_angle;
my $dist = log(hypot($x,$y));
my $delta_dist = $dist - $prev_dist;
printf "%d %d,%d %.1f %+.3f %.3f %+.5f\n",
$level, $x, $y, $angle, $delta_angle,
$dist, $delta_dist;
$prev_angle = $angle;
$prev_dist = $dist;
}
exit 0;
}
Math-PlanePath-113/devel/number-fraction.pl 0000644 0001750 0001750 00000002470 11663776631 016451 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use lib '/so/perl/number-fraction/number-fraction/lib/';
use Number::Fraction;
print Number::Fraction->VERSION,"\n";
# uncomment this to run the ### lines
use Smart::Comments;
{
my $x = Number::Fraction->new('4/3');
my $y = Number::Fraction->new('2/1');
my $pow = $x ** $y;
print "pow: $pow\n";
exit 0;
}
{
my $x = Number::Fraction->new('0/2');
my $y = Number::Fraction->new('0/1');
my $eq = ($x == $y);
print "equal: $eq\n";
exit 0;
}
{
my $nf = Number::Fraction->new('4/-3');
print "$nf\n";
$nf = int($nf);
print "$nf ",ref($nf),"\n";
exit 0;
}
Math-PlanePath-113/devel/bigint-lite.pl 0000644 0001750 0001750 00000003022 12007401242 015527 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Devel::TimeThis;
use Math::BigInt::Lite;
{
# sprintf about 2x faster
my $start = 0xFFFFFFF;
my $end = $start + 0x10000;
{
my $t = Devel::TimeThis->new('sprintf');
foreach ($start .. $end) {
my $n = $_;
my @array = reverse split //, sprintf('%b',$n);
}
}
{
my $t = Devel::TimeThis->new('division');
foreach ($start .. $end) {
my $n = $_;
my @ret;
do {
my $digit = $n % 2;
push @ret, $digit;
$n = int(($n - $digit) / 2);
} while ($n);
}
}
exit 0;
}
{
{
my $t = Devel::TimeThis->new('main');
foreach (1 .. 10000) {
Math::BigInt::Lite->newXX(123);
}
}
{
my $t = Devel::TimeThis->new('lite');
foreach (1 .. 10000) {
Math::BigInt::Lite->new(123);
}
}
exit 0;
}
Math-PlanePath-113/devel/wythoff-array.pl 0000644 0001750 0001750 00000022302 12240271436 016135 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::WythoffArray;
use lib 't','xt';
# uncomment this to run the ### lines
# use Smart::Comments;
{
# tree A230871
require Math::PlanePath::WythoffArray;
my $wythoff = Math::PlanePath::WythoffArray->new (x_start => 1, y_start => 1);
my @parent = (undef, 0);
my @value = (0, 1);
my @child_left = (1);
my @child_right = (undef);
my $value_seen = '';
{
my @pending = (1);
foreach (0 .. 13) {
my @new_pending;
while (@pending) {
my $i = shift @pending;
my $value = $value[$i] // die "oops no value at $i";
if ($value < 20000) { vec($value_seen,$value,1) = 1; }
my $parent_i = $parent[$i];
my $parent_value = $value[$parent_i];
{
my $left_value = $value + $parent_value;
my $left_i = scalar(@value);
$value[$left_i] = $left_value;
$parent[$left_i] = $i;
$child_left[$i] = $left_i;
push @new_pending, $left_i;
}
{
my $right_value = 3*$value - $parent_value;
my $right_i = scalar(@value);
$value[$right_i] = $right_value;
$parent[$right_i] = $i;
$child_right[$i] = $right_i;
push @new_pending, $right_i;
}
}
@pending = @new_pending;
}
}
print "total nodes ",scalar(@value),"\n";
my @rows;
{
# by rows
my @pending = (0);
while (@pending) {
my @new_pending;
my @row;
while (@pending) {
my $i = shift @pending;
if (defined $child_left[$i]) {
push @new_pending, $child_left[$i];
}
if (defined $child_right[$i]) {
push @new_pending, $child_right[$i];
}
my $value = $value[$i];
push @row, $value;
if (@row < 20) {
printf '%4d,', $value;
}
}
print "\n";
@pending = @new_pending;
push @rows, \@row;
}
}
# print columns
{
foreach my $c (0 .. 20) {
print "col c=$c: ";
foreach my $r (0 .. 20) {
if (defined (my $value = $rows[$r]->[$c])) {
print "$value,";
}
}
print "\n";
}
}
my @wythoff_row;
my @wythoff_step;
my @triangle;
{
# wythoff row
my $r = 0;
my $c = 0;
my %seen;
my $print_c_limit = 300;
for (;;) {
my $v1 = $rows[$r]->[$c];
if (! defined $v1) {
$r++;
if ($c < $print_c_limit) {
print "next row\n";
}
next;
}
my $v2 = $rows[$r+1]->[$c];
if (! defined $v2) {
last;
}
if ($v1 <= $v2) {
print "smaller v1: $v1 $v2\n";
}
$triangle[$v1][$v2] = 1;
my ($x,$y,$step) = pair_to_wythoff_xy($v1,$v2);
$x //= '[undef]';
$y //= '[undef]';
my $wv1 = $wythoff->xy_to_n($x,$y);
my $wv2 = $wythoff->xy_to_n($x+1,$y);
if ($c < $print_c_limit) {
print "$c $v1,$v2 $x, $y $step is $wv1, $wv2\n";
}
if ($c < 40) {
push @wythoff_row, $y;
push @wythoff_step, $step;
}
if (defined $seen{$y}) {
print "seen $y at $seen{$y}\n";
}
$seen{$y} = $c;
$c++;
}
print "stop at column $c\n";
print "\n";
}
{
# print triangle
foreach my $v1 (reverse 0 .. 80) {
foreach my $v2 (0 .. 80) {
print $triangle[$v1][$v2] ? '*' : ' ';
}
print "\n";
}
}
@wythoff_row = sort {$a<=>$b} @wythoff_row;
foreach (1, 2) {
print join(',',@wythoff_row),"\n";
{
require Math::NumSeq::Fibbinary;
my $fib = Math::NumSeq::Fibbinary->new;
print join(',',map{sprintf '%b',$fib->ith($_)} @wythoff_row),"\n";
}
foreach (@wythoff_row) { $_-- }
print "\n";
}
print "step: ",join(',',@wythoff_step),"\n";
require MyOEIS;
MyOEIS::compare_values
(anum => 'A230872',
name => 'tree all values occurring',
max_count => 700,
func => sub {
my ($count) = @_;
my @got = (0);
for (my $i = 0; @got < $count; $i++) {
if (vec($value_seen,$i,1)) {
push @got, $i;
}
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A230871',
name => 'tree table',
func => sub {
my ($count) = @_;
my @got;
my $r = 0;
my $c = 0;
while (@got < $count) {
my $row = $rows[$r] // last;
if ($c > $#$row) {
$r++;
$c = 0;
next;
}
push @got, $row->[$c];
$c++;
}
return \@got;
});
exit 0;
sub pair_to_wythoff_xy {
my ($v1,$v2) = @_;
foreach my $step (0 .. 500) {
# use Smart::Comments;
### at: "seek $v1, $v2 step $_"
if (my ($x,$y) = $wythoff->n_to_xy($v1)) {
my $wv2 = $wythoff->xy_to_n($x+1,$y);
if (defined $wv2 && $wv2 == $v2) {
### found: "pair $v1 $v2 at x=$x y=$x"
return ($x,$y,$step);
}
}
($v1,$v2) = ($v2,$v1+$v2);
}
}
}
{
# left-justified shift amount
require Math::NumSeq::Fibbinary;
my $fib = Math::NumSeq::Fibbinary->new;
my $path = Math::PlanePath::WythoffArray->new;
foreach my $y (0 .. 50) {
my $a = $path->xy_to_n(0,$y);
my $b = $path->xy_to_n(1,$y);
my $count = 0;
while ($a < $b) {
($a,$b) = ($b-$a,$a);
$count++;
}
my $y_fib = sprintf '%b',$fib->ith($y);
print "$y $y_fib $count\n";
# $count = ($count+1)/2;
# print "$count,";
}
exit 0;
}
{
# Y*phi
use constant PHI => (1 + sqrt(5)) / 2;
my $path = Math::PlanePath::WythoffArray->new (y_start => 0);
foreach my $y ($path->y_minimum .. 20) {
my $n = $path->xy_to_n(0,$y);
my $prod = int(PHI*PHI*$y + PHI);
print "$y $n $prod\n";
}
exit 0;
}
{
# dual
require Math::NumSeq::Fibbinary;
my $seq = Math::NumSeq::Fibbinary->new;
foreach my $value
(
1 .. 300,
1,
# # 1,10
# 4, 6, 10, 16, 26, 42, 68, 110, 178, 288, 466 # 101,1001
# 7, 11, 18, 29, 47, 76, 123, 199, 322, 521, 843 # 1010,10100
# 9, 14, 23, 37, 60, 97, 157, 254, 411, 665, 1076, # 10001,100001
# 12, 19, 31, 50, 81, 131, 212, 343, 555, 898, 1453 # 10101,101001
) {
my $z = $seq->ith($value);
printf "%3d %6b\n", $value, $z;
}
exit 0;
}
{
# Fibbinary with even trailing 0s
require Math::NumSeq::Fibbinary;
require Math::NumSeq::DigitCountLow;
my $seq = Math::NumSeq::Fibbinary->new;
my $cnt = Math::NumSeq::DigitCountLow->new (radix => 2, digit => 0);
my $e = 0;
foreach (1 .. 40) {
my ($i, $value) = $seq->next;
my $c = $cnt->ith($value);
my $str = ($c % 2 ? 'odd' : 'even');
my $ez = $seq->ith($e);
if ($c % 2 == 0) {
printf "%2d %6b %s [%d] %5b\n", $i, $value, $str, $c, $ez;
} else {
printf "%2d %6b %s [%d]\n", $i, $value, $str, $c;
}
if ($c % 2 == 0) {
$e++;
}
}
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::PowerArray;
my $path;
my $radix = 3;
my $width = 9;
$path = Math::PlanePath::PowerArray->new (radix => $radix);
foreach my $y (reverse 0 .. 6) {
foreach my $x (0 .. 5) {
my $n = $path->xy_to_n($x,$y);
my $nb = sprintf '%*s', $width, Math::BaseCnv::cnv($n,10,$radix);
print $nb;
}
print "\n";
}
exit 0;
}
{
# max Dir4
require Math::BaseCnv;
print 4-atan2(2,1)/atan2(1,1)/2,"\n";
require Math::NumSeq::PlanePathDelta;
my $realpart = 3;
my $radix = $realpart*$realpart + 1;
my $planepath = "WythoffArray";
$planepath = "GcdRationals,pairs_order=rows_reverse";
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
delta_type => 'Dir4');
my $dx_seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
delta_type => 'dX');
my $dy_seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
delta_type => 'dY');
my $max = -99;
for (1 .. 1000000) {
my ($i, $value) = $seq->next;
$value = -$value;
if ($value > $max) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dy && $dx/$dy;
printf "%d %s %.5f %s %s %.3f\n", $i, $ri, $value, $rdx,$rdy, $f;
$max = $value;
}
}
exit 0;
}
Math-PlanePath-113/devel/filled-rings.pl 0000644 0001750 0001750 00000002636 11720341360 015716 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::PlanePath::FilledRings;
# uncomment this to run the ### lines
use Smart::Comments;
{
# average diff step
my $path = Math::PlanePath::FilledRings->new;
my $prev_n = $path->xy_to_n(0,0);
my $prev_loop = $path->xy_to_n(0,0);
my $diff_total = 0;
my $diff_count = 0;
foreach my $x (1 .. 500) {
my $n = $path->xy_to_n($x,0);
my $loop = $n - $prev_n;
my $diff = $loop - $prev_loop;
#printf "%2d %3d %3d %3d\n", $x, $n, $loop, $diff;
$prev_n = $n;
$prev_loop = $loop;
$diff_total += $diff;
$diff_count++;
}
my $avg = $diff_total/$diff_count;
my $sqavg = $avg*$avg;
print "diff average $avg squared $sqavg\n";
exit 0;
}
Math-PlanePath-113/devel/dragon-iterative.gri 0000644 0001750 0001750 00000003757 12176314506 016766 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
`bit_above_lowest_zero &.n.'
Change .n. to 0 or 1 being the bit above the least significant 0 bit of .n.
If .n. is 0 then the result is 0 since the low bit is 0 and above that also 0.
{
while {rpn \.word1. 2 remainder}
\.word1. = {rpn \.word1. 1 - 2 /}
end while
\.word1. = {rpn \.word1. 2 / 2 remainder}
}
`Draw Dragon length .length.'
Draw a dragon curve starting at 0,0 with .length. many segments, each
segment being 1 long.
{
new .length. .i. .tmp. .x. .y. .dx. .dy.
.length. = \.word3.
.x. = 0
.y. = 0
.dx. = 1
.dy. = 0
# loop i=0 to i=length inclusive
.i. = 0
while {rpn .i. .length. >=}
draw line from .x. .y. to {rpn .x. .dx. +} {rpn .y. .dy. +}
.x. += .dx.
.y. += .dy.
# (dx,dy) = (-dy,dx) turn left +90 degrees
.tmp. = .dx.
.dx. = {rpn 0 .dy. -}
.dy. = .tmp.
# if bit above lowest 0 then (dx,dy) = (-dx,-dy) rotate 180 so
# turn is right -90 degrees instead
.tmp. = .i.
bit_above_lowest_zero &.tmp.
if .tmp.
.dx. = {rpn 0 .dx. -}
.dy. = {rpn 0 .dy. -}
end if
.i. += 1
end while
delete .length. .i. .tmp. .x. .y. .dx. .dy.
}
set x axis -12 24 4
set y axis -18 18 4
Draw Dragon length 256
# show .i. " " .bit.
Math-PlanePath-113/devel/vertical.pl 0000644 0001750 0001750 00000005141 11520123441 015136 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use POSIX 'fmod';
use Math::BigRat;
use Math::Prime::XS;
#use Smart::Comments;
use constant PHI => (1 + sqrt(5)) / 2;
# (3n-1)*n/2 pentagonal
# (3n+1)*n/2 second pentagonal
# http://www.research.att.com/~njas/sequences/A005449
# sum of n consecutive numbers >= n (n+1)+(n+2)+...+(n+n)
# triangular+square (n+1)*n/2 + n*n
# (3n+1)*n/2-2 = offset (3n+7)*n/2
# http://www.research.att.com/~njas/sequences/A140090
# sum n+1 to n+n-3 or some such
# (3n+1)*n/2
# (3n+1)*n/2 - 1
# (3n+1)*n/2 - 2
sub three {
my ($i) = @_;
return (3*$i+1)*$i/2 - 2;
}
sub is_perfect_square {
my ($n) = @_;
$n = sqrt($n);
return ($n == int($n));
}
{
my $prev_k = 0;
foreach my $k (0 .. 1000) {
my $sq = 24*$k+1;
if (is_perfect_square($sq)) {
printf "%4d %+4d %4d %4d\n", $k, $k-$prev_k, $k%24, $sq;
$prev_k = $k;
}
}
exit 0;
}
{
# i==0mod4 or 1mod4 always even
#
foreach my $k (0 .. 100) {
my $i = 4*$k + 2;
my $n = three($i);
my $factors = factorize($n);
printf "%4d %4d %s\n", $i,$n,$factors;
# unless ($factors =~ /\Q*/) {
# die;
# }
}
exit 0;
}
{
local $, = ',';
print map {three($_)} 0..20;
exit 0;
}
{
my $a = Math::BigRat->new('3/2');
my $b = Math::BigRat->new('1/2');
my $c = Math::BigRat->new('-2');
my $x = -$b;
my $sq = ($b*$b-4*$a*$c);
my $y = $sq;
$y->bsqrt;
print "$x $sq $y\n";
my $r1 = ($x + $y)/(2*$a);
my $r2 = ($x - $y)/(2*$a);
print "$r1 $r2\n";
exit 0;
}
{
foreach my $i (5 .. 500) {
my $n = three($i);
if (Math::Prime::XS::is_prime($n)) {
say "$i $n";
last;
}
}
exit 0;
}
sub factorize {
my ($n) = @_;
my @factors;
foreach my $f (2 .. int(sqrt($n)+1)) {
while (($n % $f) == 0) {
push @factors, $f;
### $n
$n /= $f;
}
}
if ($n != 1) {
push @factors, $n;
}
return join ('*',@factors);
}
exit 0;
Math-PlanePath-113/devel/cellular-rule-xpm.pl 0000644 0001750 0001750 00000003412 11646222723 016712 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use strict;
use Image::Base::PNGwriter;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
#use Devel::Comments;
my $white = '#FFFFFF';
$white = 'white';
my $class = 'Image::Base::PNGwriter';
$class = 'Image::Xpm';
eval "require $class; 1" or die;
my $rule = 30;
my @table = map {($rule & (1<<$_)) ? 1 : 0} 0 .. 7;
print join(',',@table),"\n";
my $height = 500;
my $width = 2*$height;
my $image = $class->new (-width => $width, -height => $height);
$image->rectangle(0,0,$width-1,$height-1, 'black', 1);
# $image->xy($size-2,0,$white); # right
$image->xy(int(($width-1)/2),0,$white); # centre
foreach my $y (1..$height-1) {
foreach my $x (0 .. $width-1) {
my $p = 0;
foreach my $o (-1,0,1) {
$p *= 2;
### x: $x+$o
### y: $y-1
### cell: $image->xy($x+$o,$y-1)
### cell: $image->xy($x+$o,$y-1) eq $white
$p += ($image->xy(min(max($x+$o,0),$width-1),$y-1) eq $white);
}
### $p
if ($table[$p]) {
$image->xy($x,$y,'white');
}
}
}
$image->save('/tmp/x');
system ('xzgv /tmp/x');
exit 0;
# vec()
Math-PlanePath-113/devel/lib/ 0002755 0001750 0001750 00000000000 12255673733 013563 5 ustar gg gg Math-PlanePath-113/devel/lib/Math/ 0002755 0001750 0001750 00000000000 12255673733 014454 5 ustar gg gg Math-PlanePath-113/devel/lib/Math/SquareRadical.pm 0000644 0001750 0001750 00000011414 12250720133 017507 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::SquareRadical;
use 5.004;
use strict;
use Carp;
use Scalar::Util 'blessed';
use vars '$VERSION', '@ISA';
$VERSION = 113;
# uncomment this to run the ### lines
use Smart::Comments;
use overload
'""' => \&stringize;
'0+' => \&numize;
'bool' => \&bool;
# '<=>' => \&spaceship;
'neg' => \&neg;
'+' => \&add,
'-' => \&sub,
'*' => \&mul,
fallback => 1;
sub new {
my ($class, $int, $factor, $root) = @_;
$factor ||= 0;
$root ||= 0;
unless ($root >= 0) {
croak "Negative root for SquareRadical";
}
return bless [ $int, $factor, $root ], $class;
}
sub bool {
my ($self) = @_;
### bool(): @$self
return $self->[0] || $self->[1];
}
sub numize {
my ($self) = @_;
### numize(): @$self
return ($self->[0] + $self->[1]*sqrt($self->[2])) + 0;
}
sub stringize {
my ($self) = @_;
### stringize(): @$self
my $factor = $self->[1];
if ($factor == 0) {
return "$self->[0]";
} else {
return "$self->[0]".($factor >= 0 ? '+' : '').$factor."*sqrt($self->[2])";
}
}
# a+b*sqrt(c) <=> d
# b*sqrt(c) <=> d-a
# b^2*c <=> (d-a)^2 # if both same sign
#
# a+b*sqrt(c) <=> d+e*sqrt(f)
# (a-d)+b*sqrt(c) <=> e*sqrt(f)
# (a-d)^2 + 2*(a-d)*b*sqrt(c) + b^2*c <=> e^2*f
# 2*(a-d)*b*sqrt(c) <=> e^2*f - b^2*c - (a-d)^2
# 4*(a-d)^2*b^2*c <=> (e^2*f - b^2*c - (a-d)^2)^2
#
sub spaceship {
my ($self, $other) = @_;
### spaceship() ...
if (blessed($other) && $other->isa('Math::SquareRadical')) {
if ($self->[1] != $other->[1]) {
croak "Different roots";
}
return bless [ $self->[0] + $other->[0],
$self->[1] + $other->[1] ];
} else {
my $factor = $self->[1];
my $rhs = ($other - $self->[0]);
return (($rhs < 0) <=> ($factor < 0)
|| (($factor*$factor*$self->[2] <=> $rhs*$rhs)
* ($rhs < 0 ? -1 : 1)));
}
}
sub neg {
my ($self) = @_;
### neg(): @$self
return $self->new(- $self->[0],
- $self->[1],
$self->[2]);
}
# c = g^2*f
# a+b*sqrt(c) + d+e*sqrt(f)
# = a+d + b*g*sqrt(f) + e*sqrt(f)
# = (a+d) + (b*g + e)*sqrt(f)
#
sub add {
my ($self, $other) = @_;
### add(): @$self
if (blessed($other) && $other->isa('Math::SquareRadical')) {
my $root1 = $self->[2];
my $root2 = $other->[2];
if ($root1 % $root2 == 0) {
$self->new($self->[0] + $other->[0],
($root1/$root2)*$self->[1] + $other->[1],
$root2);
} elsif ($root1 % $root2 == 0) {
$self->new($self->[0] + $other->[0],
($root1/$root2)*$self->[1] + $other->[1],
$root2);
} else {
croak "Different roots";
}
} else {
return $self->new($self->[0] + $other, $self->[1], $self->[2]);
}
}
# sub sub {
# my ($self, $other, $swap) = @_;
# my $ret;
# if (blessed($other) && $other->isa('Math::SquareRadical')) {
# if ($self->[1] != $other->[1]) {
# croak "Different roots";
# }
# $ret = bless [ $self->[0] - $other->[0],
# $self->[1] - $other->[1] ];
# } else {
# $ret = bless [ $self->[0] - $other, $self->[1] ];
# }
# if ($swap) {
# $ret->[0] = - $ret->[0];
# $ret->[1] = - $ret->[1];
# }
# return $ret;
# }
# (a + b*sqrt(c))*(d + e*sqrt(f))
# = a*d + b*d*sqrt(c) + a*e*sqrt(f) + b*e*sqrt(c*f)
# if c=g^2*f
# = a*d + b*d*g*sqrt(f) + a*e*sqrt(f) + b*e*g*f
sub mul {
my ($self, $other) = @_;
### mul(): @$self
if (blessed($other) && $other->isa('Math::SquareRadical')) {
my $root1 = $self->[2];
my $root2 = $other->[2];
if ($root1 % $root2 == 0) {
my $g2 = $root1/$root2;
my $g = sqrt($g2);
if ($g*$g == $g2) {
$self->new($self->[0] + $other->[0],
$g*$self->[1] + $other->[1],
$root2);
}
} elsif ($root2 % $root1 == 0) {
my $g2 = $root2/$root1;
my $g = sqrt($g2);
if ($g*$g == $g2) {
$self->new($self->[0] + $other->[0],
$self->[1] + $g*$other->[1],
$root1);
}
} else {
croak "Different roots";
}
} else {
return $self->new($self->[0] * $other, $self->[1] * $other, $self->[2]);
}
}
Math-PlanePath-113/devel/lib/Math/PlanePath/ 0002755 0001750 0001750 00000000000 12255673733 016330 5 ustar gg gg Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffPreliminaryTriangle-oeis.t 0000644 0001750 0001750 00000004773 12112610147 024771 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
MyTestHelpers::nowarnings();
use MyOEIS;
use Math::PlanePath::WythoffPreliminaryTriangle;
#------------------------------------------------------------------------------
# A165359 column 1 of left justified Wythoff, gives preliminary triangle Y
MyOEIS::compare_values
(anum => 'A165359',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffPreliminaryTriangle->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A165360 column 2 of left justified Wythoff, gives preliminary triangle X
MyOEIS::compare_values
(anum => 'A165360',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffPreliminaryTriangle->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x;
}
return \@got;
});
#------------------------------------------------------------------------------
# A166309 Preliminary Wythoff Triangle, N by rows
MyOEIS::compare_values
(anum => 'A166309',
func => sub {
my ($count) = @_;
require Math::PlanePath::PyramidRows;
my $path = Math::PlanePath::WythoffPreliminaryTriangle->new;
my $rows = Math::PlanePath::PyramidRows->new (step=>1);
my @got;
for (my $r = $rows->n_start; @got < $count; $r++) {
my ($x,$y) = $rows->n_to_xy($r); # by rows
$y += 1;
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/devel/lib/Math/PlanePath/R7DragonCurve.pm 0000644 0001750 0001750 00000016305 12250720133 021277 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=R7DragonCurve --all --scale=10
# cf A176405 R7 turns
# A176416 R7B turns
package Math::PlanePath::R7DragonCurve;
use 5.004;
use strict;
use List::Util 'min'; # 'max'
*max = \&Math::PlanePath::_max;
use Math::PlanePath;
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest',
'xy_is_even';
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh';
use vars '$VERSION', '@ISA';
$VERSION = 113;
@ISA = ('Math::PlanePath');
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant parameter_info_array =>
[ { name => 'type',
share_key => 'type_r7dragon',
display => 'Type',
type => 'enum',
default => 'A',
choices => ['A','B'],
},
{ name => 'arms',
share_key => 'arms_6',
display => 'Arms',
type => 'integer',
minimum => 1,
maximum => 6,
default => 1,
width => 1,
description => 'Arms',
} ];
use constant dx_minimum => -2;
use constant dx_maximum => 2;
use constant dy_minimum => -1;
use constant dy_maximum => 1;
#------------------------------------------------------------------------------
sub new {
my $self = shift->SUPER::new(@_);
$self->{'arms'} = max(1, min(6, $self->{'arms'} || 1));
$self->{'type'} ||= 'A';
return $self;
}
my @dir6_to_si = (1,0,0, -1,0,0);
my @dir6_to_sj = (0,1,0, 0,-1,0);
my @dir6_to_sk = (0,0,1, 0,0,-1);
# F0F1F1F0F0F1F, 0->0, 1->1
#
# 14 12
# \ / \
# \/ \
# 13,10--11,8
# \ / \
# 9/ \
# 2----3,6----7 i=+2,j=+1
# \ / \
# \ / \
# 0----1,4----5
#
# 0 1 2 3 4 5
# B 5----6,3----7 i=+2,j=+1
# \ / \
# \ / \
# 0----1,4----2
#
# 0 1 2 3 4 5
my @digit_to_i = (0,1,0,1,1,2,1);
my @digit_to_j = (0,0,1,1,0,0,1);
my @digit_to_rot = (0,1,0,-1,0,1,0);
# 0 1 2 3 4 5 6
my @digit_b_to_a = (0,4,5,3,1,2,6);
sub n_to_xy {
my ($self, $n) = @_;
### R7DragonCurve n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n, $n); }
my $zero = ($n * 0); # inherit bignum 0
my $i = 0;
my $j = 0;
my $k = 0;
my $si = $zero;
my $sj = $zero;
my $sk = $zero;
# initial rotation from arm number
{
my $int = int($n);
my $frac = $n - $int; # inherit possible BigFloat
$n = $int; # BigFloat int() gives BigInt, use that
my $rot = _divrem_mutate ($n, $self->{'arms'});
my $s = $zero + 1; # inherit bignum 1
if ($rot >= 3) {
$s = -$s; # rotate 180
$frac = -$frac;
$rot -= 3;
}
if ($rot == 0) { $i = $frac; $si = $s; } # rotate 0
elsif ($rot == 1) { $j = $frac; $sj = $s; } # rotate +60
else { $k = $frac; $sk = $s; } # rotate +120
}
foreach my $digit (digit_split_lowtohigh($n,7)) {
### at: "$i,$j,$k side $si,$sj,$sk"
### $digit
if ($self->{'type'} eq 'B') {
$digit = $digit_b_to_a[$digit];
}
if ($digit == 1) {
($i,$j,$k) = (-$j,-$k,$i); # rotate +120
$i += $si;
$j += $sj;
$k += $sk;
} elsif ($digit == 2) {
$i -= $sk;
$j += $si;
$k += $sj;
} elsif ($digit == 3) {
($i,$j,$k) = ($k,-$i,-$j);
$i += $si;
$j += $sj;
$k += $sk;
$i -= $sk;
$j += $si;
$k += $sj;
} elsif ($digit == 4) {
$i += $si;
$j += $sj;
$k += $sk;
} elsif ($digit == 5) {
($i,$j,$k) = (-$j,-$k,$i); # rotate +120
$i += 2*$si;
$j += 2*$sj;
$k += 2*$sk;
} elsif ($digit == 6) {
$i += $si;
$j += $sj;
$k += $sk;
$i -= $sk;
$j += $si;
$k += $sj;
}
# $i += $digit_to_i[$digit];
# $j += $digit_to_j[$digit];
# multiple 2i+j
($si,$sj,$sk) = (2*$si - $sk,
2*$sj + $si,
2*$sk + $sj);
}
### final: "$i,$j,$k side $si,$sj,$sk"
### is: (2*$i + $j - $k).",".($j+$k)
return (2*$i + $j - $k, $j+$k);
}
# all even points when arms==6
sub xy_is_visited {
my ($self, $x, $y) = @_;
return 0;
if ($self->{'arms'} == 6) {
return xy_is_even($self,$x,$y);
} else {
return defined($self->xy_to_n($x,$y));
}
}
# maximum extent -- no, not quite right
#
# .----*
# \
# *----.
#
# Two triangle heights, so
# rnext = 2 * r * sqrt(3)/2
# = r * sqrt(3)
# rsquared_next = 3 * rsquared
# Initial X=2,Y=0 is rsquared=4
# then X=3,Y=1 is 3*3+3*1*1 = 9+3 = 12 = 4*3
# then X=3,Y=3 is 3*3+3*3*3 = 9+3 = 36 = 4*3^2
#
my @try_dx = (2, 1, -1, -2, -1, 1);
my @try_dy = (0, 1, 1, 0, -1, -1);
sub xy_to_n {
return scalar((shift->xy_to_n_list(@_))[0]);
}
sub xy_to_n_list {
my ($self, $x, $y) = @_;
### R7DragonCurve xy_to_n_list(): "$x, $y"
return;
$x = round_nearest($x);
$y = round_nearest($y);
if (is_infinite($x)) {
return $x; # infinity
}
if (is_infinite($y)) {
return $y; # infinity
}
my @n_list;
my $xm = 2*$x; # doubled out
my $ym = 2*$y;
foreach my $i (0 .. $#try_dx) {
my $t = $self->Math::PlanePath::R7DragonMidpoint::xy_to_n
($xm+$try_dx[$i], $ym+$try_dy[$i]);
### try: ($xm+$try_dx[$i]).",".($ym+$try_dy[$i])
### $t
next unless defined $t;
my ($tx,$ty) = n_to_xy($self,$t) # not a method for R7DragonRounded
or next;
if ($tx == $x && $ty == $y) {
### found: $t
if (@n_list && $t < $n_list[0]) {
unshift @n_list, $t;
} elsif (@n_list && $t < $n_list[-1]) {
splice @n_list, -1,0, $t;
} else {
push @n_list, $t;
}
if (@n_list == 3) {
return @n_list;
}
}
}
return @n_list;
}
# minimum -- no, not quite right
#
# *----------*
# \
# \ *
# * \
# \
# *----------*
#
# width = side/2
# minimum = side*sqrt(3)/2 - width
# = side*(sqrt(3)/2 - 1)
#
# minimum 4/9 * 2.9^level roughly
# h = 4/9 * 2.9^level
# 2.9^level = h*9/4
# level = log(h*9/4)/log(2.9)
# 3^level = 3^(log(h*9/4)/log(2.9))
# = h*9/4, but big bigger for log
#
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### R7DragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $xmax = int(max(abs($x1),abs($x2)));
my $ymax = int(max(abs($y1),abs($y2)));
return (0,
($xmax*$xmax + 3*$ymax*$ymax + 1)
* 1/5
* $self->{'arms'});
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/FourReplicate.pm 0000644 0001750 0001750 00000006441 12250720133 021413 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Working. But what is this properly called?
# strips N mod 3 (X-Y)/2 == N mod 3
package Math::PlanePath::FourReplicate;
use 5.004;
use strict;
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use Math::PlanePath;
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest',
'xy_is_even';
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
use vars '$VERSION', '@ISA';
$VERSION = 113;
@ISA = ('Math::PlanePath');
# uncomment this to run the ### lines
# use Smart::Comments;
use constant n_start => 0;
#------------------------------------------------------------------------------
my @digit_to_x = (0,2,-1,-1);
my @digit_to_y = (0,0, 1,-1);
sub n_to_xy {
my ($self, $n) = @_;
### FourReplicate n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n, $n); }
my $zero = ($n * 0); # inherit bignum 0
my $x = my $y = $zero;
my $len = $zero + 1;
foreach my $digit (digit_split_lowtohigh($n,4)) {
$x += $len * $digit_to_x[$digit];
$y += $len * $digit_to_y[$digit];
$len = -2*$len;
}
return ($x, $y);
}
# all even points when arms==6
*xy_is_visited = \&xy_is_even;
# -1,1
# * . * .
# \
# . *-.-* 2,0
# /
# * . * .
# -1,-1
#
# $x % 4
# $y % 4
#
# 3 | 2 3
# 2 | 1 0
# 1 | 3 2
# 0 | 0 1
# +---------------
# 0 1 2 3
my @yx_to_digit = ([ 0, undef, 1, undef ],
[ undef, 3, undef, 2 ],
[ 1, undef, 0, undef ],
[ undef, 2, undef, 3 ]);
sub xy_to_n {
my ($self, $x, $y) = @_;
$x = round_nearest($x);
$y = round_nearest($y);
if (is_infinite($x)) {
return $x; # infinity
}
if (is_infinite($y)) {
return $y; # infinity
}
my $zero = $x*0*$y;
my @ndigits;
while ($x || $y) {
### at: "x=$x y=$y"
my $ndigit = $yx_to_digit[$y%4]->[$x%4];
if (! defined $ndigit) { return undef; }
push @ndigits, $ndigit;
$x -= $digit_to_x[$ndigit];
$y -= $digit_to_y[$ndigit];
### $ndigit
### dxdy: "dx=$digit_to_x[$ndigit] dy=$digit_to_y[$ndigit]"
$x /= -2;
$y /= -2;
}
return digit_join_lowtohigh(\@ndigits,4,$zero);;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### FourReplicate rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $xmax = int(max(abs($x1),abs($x2)));
my $ymax = int(max(abs($y1),abs($y2)));
return (0, ($xmax*$xmax + 3*$ymax*$ymax + 1) * 32);
return (0, 4**6); # ($xmax*$xmax + 3*$ymax*$ymax + 1));
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/ZeckendorfTerms-oeis.t 0000644 0001750 0001750 00000003142 12132222017 022530 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
MyTestHelpers::nowarnings();
use MyOEIS;
use Math::PlanePath::ZeckendorfTerms;
#------------------------------------------------------------------------------
# A134561 by anti-diagonals
MyOEIS::compare_values
(anum => 'A134561',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::ZeckendorfTerms->new;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up',
x_start=>1,y_start=>1);
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffPreliminaryTriangle.pm 0000644 0001750 0001750 00000021366 12250720133 024202 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# x=45,y=10 x=59,y=19 dx=14,dy=9 14/9=1.55
#
# x=42,y=8 x=113,y=52 dx=71,dy=44 71/44=1.613
#
# below
# 32,12 to 36,4 sqrt((32-36)^2+(12-4)^2) = 9
# 84,34 to 99,14 sqrt((84-99)^2+(34-14)^2) = 25
# 180,64 to 216,11 sqrt((180-216)^2+(64-11)^2) = 64
#
# above
# 14,20 to 5,32 sqrt((14-5)^2+(20-32)^2) = 15 = 9*1.618 3
# 34,50 to 14,85 sqrt((34-14)^2+(50-85)^2) = 40 = 25*1.618 5
# 132,158 to 77,247 sqrt((132-77)^2+(158-247)^2) = 104 = 64*1.618 8
# 8,525 to 133,280 sqrt((8-133)^2+(525-280)^2) = 275 = 169*1.618 13
package Math::PlanePath::WythoffPreliminaryTriangle;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'bit_split_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant y_minimum => 1;
use Math::PlanePath::WythoffArray;
my $wythoff = Math::PlanePath::WythoffArray->new;
sub new {
my $self = shift->SUPER::new(@_);
$self->{'shift'} ||= 0;
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### WythoffPreliminaryTriangle n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# prev+y=x
# prev = x-y
$n -= 1;
my $y = $wythoff->xy_to_n(0,$n);
my $x = $wythoff->xy_to_n(1,$n);
while ($y <= $x) {
### at: "y=$y x=$x"
($y,$x) = ($x-$y,$y);
}
### reduction to: "y=$y x=$x"
### return: "y=$y x=$x"
return ($x, $y);
}
sub xy_is_visited {
my ($self, $x, $y) = @_;
$x = round_nearest ($x);
$y = round_nearest ($y);
return $x >= 0 && $x < $y;
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### WythoffPreliminaryTriangle xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
my $orig_x = $x;
my $orig_y = $y;
if (is_infinite($y)) { return $y; }
unless ($x >= 0 && $x < $y) {
return undef;
}
($y,$x) = ($x,$x+$y);
foreach (0 .. 500) {
($y,$x) = ($x,$x+$y);
### at: "seek y=$y x=$x"
my ($c,$r) = $wythoff->n_to_xy($y) or next;
my $wx = $wythoff->xy_to_n($c+1,$r);
if (defined $wx && $wx == $x) {
### found: "pair $y $x at c=$c r=$r"
my $n = $r+1;
my ($nx,$ny) = $self->n_to_xy($n);
### nxy: "nx=$nx, ny=$ny"
if ($nx == $orig_x && $ny == $orig_y) {
return $n;
} else {
### no match: "cf x=$x y=$y"
return undef;
}
}
}
### not found ...
return undef;
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### WythoffPreliminaryTriangle rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 1) {
### all outside first quadrant ...
return (1, 0);
}
return (1,
$self->xy_to_n(0,2*abs($y2)));
}
1;
__END__
=for stopwords eg Ryde Math-PlanePath Moore Wythoff Zeckendorf concecutive fibbinary OEIS
=head1 NAME
Math::PlanePath::WythoffPreliminaryTriangle -- table of Fibonacci recurrences
=head1 SYNOPSIS
use Math::PlanePath::WythoffPreliminaryTriangle;
my $path = Math::PlanePath::WythoffPreliminaryTriangle->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
XThis path is the Wythoff preliminary triangle by Clark
Kimberling,
=cut
# math-image --path=WythoffPreliminaryTriangle --output=numbers --all --size=60x14
=pod
13 | 105 118 131 144 60 65 70 75 80 85 90 95 100
12 | 97 110 47 52 57 62 67 72 77 82 87 92
11 | 34 39 44 49 54 59 64 69 74 79 84
10 | 31 36 41 46 51 56 61 66 71 76
9 | 28 33 38 43 48 53 58 63 26
8 | 25 30 35 40 45 50 55 23
7 | 22 27 32 37 42 18 20
6 | 19 24 29 13 15 17
5 | 16 21 10 12 14
4 | 5 7 9 11
3 | 4 6 8
2 | 3 2
1 | 1
Y=0 |
+-----------------------------------------------------
X=0 1 2 3 4 5 6 7 8 9 10 11 12
A coordinate pair Y and X are the start of a Fibonacci style recurrence,
F[1]=Y, F[2]=X F[i+i] = F[i] + F[i-1]
Such a sequence eventually becomes a row of the Wythoff array
(L) after some number of initial iterations.
The N value at X,Y is the row number of the Wythoff array which is reached
from initial Y and X. Rows are numbered starting from 1. Eg.
Y=4,X=1 sequence: 4, 1, 5, 6, 11, 17, 28, 45, ...
row 7 of WythoffArray: 17, 28, 45, ...
so N=7 at Y=4,X=1
Taking this in reverse, a given N is at an X,Y position in the triangle
according to where row number N of the Wythoff array "precurses" back to.
The Wythoff row is run in reverse,
F[i-1] = F[i+i] - F[i]
It can be shown that such a precurse always reaches a pair Y and X with
YE=1 and 0E=XEY, hence making the triangular X,Y arrangement
above.
N=7 WythoffArray row 7 is 17,28,45,73,...
go backwards from 17,28 by subtraction
11 = 28 - 17
6 = 17 - 11
5 = 11 - 6
1 = 6 - 5
4 = 5 - 1
stop on reaching 4,1 which is Y=4,X=1 satisfying Y>=1 and 0<=X=XEY
=cut
# (r-1 + floor(r*phi)) / (r-1 + 2*floor(r*phi))
# ~= (r-1+r*phi)/(r-1+2*r*phi)
# = (r*(phi+1) - 1) / (r*(2phi+1) - 1)
# -> r*(phi+1) / r*(2*phi+1)
# = (phi+1) / (2*phi+1)
# = 1/phi = 0.618
=pod
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::WythoffPreliminaryTriangle-Enew ()>
Create and return a new path object.
=back
=head1 OEIS
The Wythoff array is in Sloane's Online Encyclopedia of Integer Sequences
in various forms,
=over
L (etc)
=back
A165360 X
A165359 Y
A166309 N by rows
=head1 SEE ALSO
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/PeanoVertices.pm 0000644 0001750 0001750 00000007317 12250720133 021421 0 ustar gg gg # works, worth having separately ?
# alternating diagonals when even radix ?
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=PeanoVertices --all --output=numbers
# math-image --path=PeanoVertices,radix=5 --lines
#
package Math::PlanePath::PeanoVertices;
use 5.004;
use strict;
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh';
use Math::PlanePath::PeanoCurve;
# uncomment this to run the ### lines
# use Smart::Comments;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 1;
use constant parameter_info_array =>
[ { name => 'radix',
share_key => 'radix_3',
display => 'Radix',
type => 'integer',
minimum => 2,
default => 3,
width => 3,
} ];
sub new {
my $self = shift->SUPER::new(@_);
$self->{'radix'} ||= 3;
$self->{'peano'} = Math::PlanePath::PeanoCurve->new (radix => $self->{'radix'});
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### PeanoVertices n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
{
# ENHANCE-ME: for odd radix the ends join and the direction can be had
# without a full N+1 calculation
my $int = int($n);
### $int
### $n
if ($n != $int) {
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $frac = $n - $int; # inherit possible BigFloat
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int; # BigFloat int() gives BigInt, use that
}
my ($x,$y) = $self->{'peano'}->n_to_xy($n)
or return;
if ($x % 2) {
if ($y % 2) {
$x += 1;
$y += 1;
} else {
$x -= 0;
$y += 1;
}
} else {
if ($y % 2) {
$x += 1;
$y -= 0;
} else {
$x -= 0;
$y -= 0;
}
}
($x,$y) = (($y+$x)/2, ($y-$x)/2);
return ($x, $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### PeanoVertices xy_to_n(): "$x, $y"
return undef;
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
if (is_infinite($x)) {
return $x;
}
if (is_infinite($y)) {
return $y;
}
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
return (0, 1000);
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
### rect_to_n_range(): "$x1,$y1 to $x2,$y2"
if ($x2 < 0 || $y2 < 0) {
return (1, 0);
}
my $radix = $self->{'radix'};
my ($power, $level) = round_down_pow (max($x2,$y2)*$radix/2, $radix);
if (is_infinite($level)) {
return (0, $level);
}
return (0, 2*$power*$power - 1);
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/four-replicate.pl 0000644 0001750 0001750 00000003604 12165124417 021575 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::FourReplicate;
# uncomment this to run the ### lines
#use Smart::Comments;
{
require Math::BaseCnv;
my $path = Math::PlanePath::FourReplicate->new;
foreach my $n (0 .. 2**30) {
my ($x,$y) = $path->n_to_xy($n);
my ($n_lo,$n_hi) = $path->rect_to_n_range(0,0,$x,$y);
if ($n_hi < $n) {
my $n4 = Math::BaseCnv::cnv($n,10,4);
my $n_hi4 = Math::BaseCnv::cnv($n_hi,10,4);
print "n=$n4 outside n_hi=$n_hi4\n";
}
}
exit 0;
}
{
require Math::PlanePath::FourReplicate;
my $path = Math::PlanePath::FourReplicate->new;
my @table;
my $xmod = 4;
my $ymod = 4;
foreach my $n (0 .. 2**8) {
my ($x,$y) = $path->n_to_xy($n);
my $mx = $x % $xmod;
my $my = $y % $ymod;
my $href = ($table[$mx][$my] ||= {});
$href->{$n%4} = 1;
}
my $width = 3;
foreach my $my (reverse 0 .. $ymod-1) {
printf "%2d", $my;
foreach my $mx (0 .. $xmod-1) {
my $href = ($table[$mx][$my] ||= {});
my $str = join(',', keys %$href);
printf " %*s", $width, $str;
}
print "\n";
}
print "\n ";
foreach my $mx (0 .. $xmod-1) {
printf " %*s", $width, $mx;
}
print "\n";
exit 0;
}
Math-PlanePath-113/devel/lib/Math/PlanePath/NxNinv.pm 0000644 0001750 0001750 00000006153 12250720133 020067 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A072732
# A072733 inverse
# A072736 X coord
# A072737 Y coord
#
# A072734
# A072740 X coord
# A072741 Y coord
package Math::PlanePath::NxNinv;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
sub n_to_xy {
my ($self, $n) = @_;
### NxN n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# d = [ 0, 1, 2, 3, 4 ]
# n = [ 0, 1, 3, 6, 10 ]
# N = (d+1)*d/2
# d = (-1 + sqrt(8*$n+1))/2
#
my $d = int((sqrt(8*$n+1) - 1) / 2);
$n -= $d*($d+1)/2;
### $d
### $n
my $x = $d-$n; # downwards
my $y = $n; # upwards
my $diff = $x-$y;
### diagonals xy: "$x, $y diff=$diff"
if ($x <= $y) {
my $h = int($x/2);
return ($h,
$h + ($x%2) + 2*($y - 2*$h - ($x%2)));
} else {
my $h = int($y/2);
return (1 + $h + ($y%2) + 2*($x-1 - 2*$h - ($y%2)),
$h);
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### NxN xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
my $diff = $x-$y;
if ($diff <= 0) {
($x,$y) = (2*$x + ($diff % 2),
2*$x + int((1-$diff)/2));
} else {
### pos diff, use y ...
($x,$y) = (2*($y+1) - 1 + int($diff/2),
2*$y + (($diff+1) % 2));
}
return (($x+$y)**2 + $x+3*$y)/2;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### NxN rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
return (0, $self->xy_to_n($x2,0));
return (0, $self->xy_to_n($x2,$y2));
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffDifference.pm 0000644 0001750 0001750 00000011147 12251673622 022262 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::WythoffDifference;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant xy_is_visited => 1;
use Math::PlanePath::WythoffArray;
my $wythoff = Math::PlanePath::WythoffArray->new;
sub n_to_xy {
my ($self, $n) = @_;
### WythoffDifference n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# f1+f0 > i
# f0 > i-f1
# check i-f1 as the stopping point, so that if i=UV_MAX then won't
# overflow a UV trying to get to f1>=i
#
my @fibs;
{
my $f0 = ($n * 0); # inherit bignum 0
my $f1 = $f0 + 1; # inherit bignum 1
while ($f0 <= $n-$f1) {
($f1,$f0) = ($f1+$f0,$f1);
push @fibs, $f1; # starting $fibs[0]=1
}
}
### @fibs
my $orig_n = $n;
# indices into fib[] which are the Fibonaccis adding up to $n
my @indices;
for (my $i = $#fibs; $i >= 0; $i--) {
### at: "n=$n f=".$fibs[$i]
if ($n >= $fibs[$i]) {
push @indices, $i;
$n -= $fibs[$i];
### sub: "$fibs[$i] to n=$n"
--$i;
}
}
### @indices
my $y = 0;
my $shift;
my $x;
my $low = $indices[-1];
if ($low % 2) {
# odd trailing zeros
$x = ($low+1)/2;
$shift = $low + 2;
pop @indices;
} else {
# even trailing zeros
$x = 0;
$shift = 1;
if ($low == 0) {
pop @indices;
} else {
$y = -1;
}
}
foreach my $i (@indices) {
### y add: "ishift=".($i-$shift)." fib=".$fibs[$i-$shift]
$y += $fibs[$i-$shift];
}
### $y
return ($x, $y);
}
# 6 | 11 28 73 191 500
# 5 | 9 23 60 157 411
# 4 | 8 20 52 136 356
# 3 | 6 15 39 102 267
# 2 | 4 10 26 68 178
# 1 | 3 7 18 47 123
# 0 | 1 2 5 13 34
# +-------------------
# 0 1 2 3 4
# 9 | 100100 10001010 1000101000 100010100000 10001010000000
# 8 | 100001 10000010 1000001000 100000100000 10000010000000
# 7 | 10101 1010010 101001000 10100100000 1010010000000
# 6 | 10100 1001010 100101000 10010100000 1001010000000
# 5 | 10001 1000010 100001000 10000100000 1000010000000
# 4 | 10000 101010 10101000 1010100000 101010000000
# 3 | 1001 100010 10001000 1000100000 100010000000
# 2 | 101 10010 1001000 100100000 10010000000
# 1 | 100 1010 101000 10100000 1010000000
# 0 | 1 10 1000 100000 10000000
# +--------------------------------------------------------
# 0 1 2 3 4
sub xy_to_n {
my ($self, $x, $y) = @_;
$x = round_nearest ($x);
if ($x == 0) {
my $n1 = $wythoff->xy_to_n(1,$y);
if ($n1) {
$n1 -= $wythoff->xy_to_n(0,$y);
}
return $n1;
}
return $wythoff->xy_to_n(2*$x-1,$y);
}
# exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### WythoffDifference rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
# bottom left into first quadrant
if ($x1 < 0) { $x1 *= 0; }
if ($y1 < 0) { $y1 *= 0; }
return ($self->xy_to_n($x1,$y1), # bottom left
$self->xy_to_n($x2,$y2)); # top right
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/squares-dispersion.pl 0000644 0001750 0001750 00000005656 11770201234 022517 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::NumSeq::Squares;
# uncomment this to run the ### lines
#use Smart::Comments;
# diagonals slope=2
# Classic Sequences
# http://oeis.org/classic.html
#
# A082156
# 1 4 9 16 25 d^2
# +3 +5 +7 +9
#
# 2 6 12 20 30 (d^2 + 3 d + 2)
# +4 +6 +8 +10
#
# 3 8 15 24 35 (d^2 + 4 d + 3)
# +5 +7 +9 +11
#
# 5 11 19 29 41 (d^2 + 5 d + 5)
# +6 +8 +10 +12
#
# 7 14 23 34 47 (d^2 + 6 d + 7)
# +7 +9 +11 +13
{
# rows
my @non_squares = (0);
foreach my $n (0 .. 100) {
push @non_squares, $n if ! is_square($n);
}
print join(',',@non_squares),"\n";
# 1 4 9 16 25 36 49 64 81 100 121 144
# 2 6 12 20 30 42 56 72 90 110 132
# 3 8 15 24 35 48 63 80 99 120
# 5 11 19 29 41 55 71 89 109
# 7 14 23 34 47 62 79
# 10 18 28 40 54 70
# 13 22 33 46 61
# 17 27 39 53
# 21 32 45
# 26 38
# 31
#
# 0 1 2 3 4 5 6 7 8 9 10
my @o = (0, 0, 0, 1, 2, 4, 6, 9, 12, 16, 20);
# +0 +0 +1 +1 +2 +2 +3 +3 +4 +4
# (2x+y+2)(2x+y-2) = 4xx+4xy+yy
# N = (x+1)**2 + (x+1)*y + (y*y - 2*y + odd)/4
# = x^2 + 2x + 1+ xy + y + y^2/4 - y/2 + odd/4
# = x^2 + 2x + 1+ xy + y^2/4 + y/2 + odd/4
# = (4x^2 + 8x + 4+ 4xy + y^2 + 2y + odd)/4
# = (4x^2 + 4xy + 8x + y^2 + 2y + 4 + odd)/4
# = ((2x+y+2)^2 + 2y+odd) / 4
my @seen;
foreach my $y (0 .. 10) {
foreach my $x (0 .. 14) {
my $odd = ($y & 1);
my $o = ($odd
? ($y*$y - 2*$y + 1)/4
: ($y*$y - 2*$y)/4); # even
if ($o != $o[$y]) { die }
#my $o = ($o[$y]||0);
my $n = ($x+1)**2 + ($x+1)*$y + $o;
# my $n = ((2*$x+$y+2)**2 + 2*$y + $odd) / 4;
my $dup = ($seen[$n]++ ? '*' : ' ');
printf ' %3d%s', $n, $dup;
}
print "\n";
}
exit 0;
}
{
# non-squares
my $next_root = 1;
my $next_square = 1;
my $prev = 0;
foreach my $n (1 .. 50) {
my $non = non_square($n);
if ($non != $prev+1) {
print "--\n";
}
my $sq = is_square($non) ? ' ***' : '';
print "$non$sq\n";
$prev = $non;
}
sub non_square {
my ($n) = @_;
return $n + int(sqrt($n))-1;
}
sub is_square {
my ($n) = @_;
return Math::NumSeq::Squares->pred($n);
}
exit 0;
}
Math-PlanePath-113/devel/lib/Math/PlanePath/FibonacciWordKnott.pm 0000644 0001750 0001750 00000023007 12250720133 022375 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# http://alexis.monnerot-dumaine.neuf.fr/articles/fibonacci%20fractal.pdf
# [gone]
#
# math-image --path=FibonacciWordKnott --output=numbers_dash
package Math::PlanePath::FibonacciWordKnott;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
#use Smart::Comments;
use Math::PlanePath::FibonacciWordFractal;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
my @dir4_to_dx = (0,-1,0,1);
my @dir4_to_dy = (1,0,-1,0);
sub n_to_xy {
my ($self, $n) = @_;
### FibonacciWordKnott n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n, $n); }
# my $frac;
# {
# my $int = int($n);
# $frac = $n - $int; # inherit possible BigFloat
# $n = $int; # BigFloat int() gives BigInt, use that
# }
{
my $int = int($n);
### $int
### $n
if ($n != $int) {
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $frac = $n - $int; # inherit possible BigFloat
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int; # BigFloat int() gives BigInt, use that
}
my $zero = ($n * 0); # inherit bignum 0
my $one = $zero + 1; # inherit bignum 0
my @f = ($one, 2+$zero);
my @xend = ($zero, $zero, $one); # F3 N=2 X=1,Y=1
my @yend = ($zero, $one, $one);
my $level = 2;
while ($f[-1] < $n) {
push @f, $f[-1] + $f[-2];
my ($x,$y);
my $m = ($level % 6);
if ($m == 1) {
$x = $yend[-2]; # -90
$y = - $xend[-2];
} elsif ($m == 2) {
$x = $xend[-2]; # T -90
$y = - $yend[-2];
} elsif ($m == 3) {
$x = $yend[-2]; # T
$y = $xend[-2];
} elsif ($m == 4) {
$x = - $yend[-2]; # +90
$y = $xend[-2];
} elsif ($m == 5) {
$x = - $xend[-2]; # T +90
$y = $yend[-2];
} elsif ($m == 0) {
$x = $yend[-2]; # T
$y = $xend[-2];
}
push @xend, $xend[-1] + $x;
push @yend, $yend[-1] + $y;
### push xy: "levelmod=".($level%6)." add $x,$y for $xend[-1],$yend[-1] for f=$f[-1]"
$level++;
}
my $x = $zero;
my $y = $zero;
my $rot = 0;
my $transpose = 0;
while (@xend > 1) {
### at: "$x,$y rot=$rot transpose=$transpose level=$level n=$n consider f=$f[-1]"
my $xo = pop @xend;
my $yo = pop @yend;
if ($n >= $f[-1]) {
$n -= $f[-1];
### offset: "$xo, $yo for ".($level % 6)
if ($transpose) {
($xo,$yo) = ($yo,$xo);
}
if ($rot & 2) {
$xo = -$xo;
$yo = -$yo;
}
if ($rot & 1) {
($xo,$yo) = (-$yo,$xo);
}
### apply rot to offset: "$xo, $yo"
$x += $xo;
$y += $yo;
my $m = $level % 6;
if ($m == 1) { # F8 N=21 etc
# -90
if ($transpose) {
$rot++;
} else {
$rot--; # -90
}
} elsif ($m == 2) { # F3 N=2 etc
# T -90
if ($transpose) {
$rot++;
} else {
$rot--; # -90
}
$transpose ^= 3;
} elsif ($m == 3) { # F4 N=3 etc
$transpose ^= 3; # T
} elsif ($m == 4) { # F5 N=5 etc
# +90
if ($transpose) {
$rot--;
} else {
$rot++; # +90
}
} elsif ($m == 5) { # F6 N=8 etc
# T +90
if ($transpose) {
$rot--;
} else {
$rot++; # +90
}
$transpose ^= 3;
} else { # ($m == 0) # F7 N=13 etc
$transpose ^= 3; # T
}
}
pop @f;
$level--;
}
# mod 6 twist ?
# ### final rot: "$rot transpose=$transpose gives ".(($rot^$transpose)&3)
# $rot = ($rot ^ $transpose) & 3;
# $x = $frac * $dir4_to_dx[$rot] + $x;
# $y = $frac * $dir4_to_dy[$rot] + $y;
### final with frac: "$x,$y"
return ($x,$y);
}
my $moffset = 1;
#use Smart::Comments;
sub xy_to_n {
my ($self, $x, $y) = @_;
### FibonacciWordKnott xy_to_n(): "$x, $y"
$x = round_nearest($x);
if (is_infinite($x)) {
return $x;
}
$y = round_nearest($y);
if (is_infinite($y)) {
return $y;
}
foreach my $xoffset (1,0,-1) {
foreach my $yoffset (1,0,-1) {
### try: "x=".(2*$y+$yoffset)." y=".(2*$x+$xoffset)
if (defined (my $n = $self->Math::PlanePath::FibonacciWordFractal::xy_to_n(2*$x+$xoffset, 2*$y+$yoffset))) {
### $n
if (my ($nx,$ny) = $self->n_to_xy($n)) {
### rev: "nx=$nx,ny=$ny"
if ($nx == $x && $ny == $y) {
return $n;
}
}
}
}
}
return undef;
no Smart::Comments;
my $zero = ($x * 0 * $y); # inherit bignum 0
my $one = $zero + 1; # inherit bignum 0
my @f = ($one, $zero+2);
my @xend = ($zero, $one); # F3 N=2 X=1,Y=1
my @yend = ($one, $one);
my $level = 3;
for (;;) {
my ($xo,$yo);
my $m = ($level-$moffset) % 6;
### $m
if ($m == 2) {
$xo = $yend[-2]; # T
$yo = $xend[-2];
} elsif ($m == 3) {
$xo = $yend[-2]; # -90
$yo = - $xend[-2];
} elsif ($m == 4) {
$xo = $xend[-2]; # T -90
$yo = - $yend[-2];
} elsif ($m == 5) {
### T
$xo = $yend[-2]; # T
$yo = $xend[-2];
} elsif ($m == 0) {
$xo = - $yend[-2]; # +90
$yo = $xend[-2];
} elsif ($m == 1) {
$xo = - $xend[-2]; # T +90
$yo = $yend[-2];
}
$xo += $xend[-1];
$yo += $yend[-1];
last if ($xo > $x && $yo > $y);
push @f, $f[-1] + $f[-2];
push @xend, $xo;
push @yend, $yo;
$level++;
### new: "level=$level $xend[-1],$yend[-1] for N=$f[-1]"
}
### @xend
### @yend
my $n = 0;
while ($level >= 2) {
### at: "$x,$y n=$n level=$level consider $xend[-1],$yend[-1] for $f[-1]"
if (($level+3-$moffset) % 6 < 3) {
### 3,4,5 X ...
if ($x >= $xend[-1]) {
$n += $f[-1];
$x -= $xend[-1];
$y -= $yend[-1];
### shift to: "$x,$y levelmod ".($level % 6)
if (($level % 6) == 3) { # F3 N=2 etc
($x,$y) = (-$y,$x); # +90
} elsif (($level % 6) == 4) { # F4 N=3 etc
$y = -$y; # +90 T
} elsif (($level % 6) == 5) { # F5 N=5 etc
($x,$y) = ($y,$x); # T
}
### rot to: "$x,$y"
if ($x < 0 || $y < 0) {
return undef;
}
}
} else {
### 0,1,2 Y ...
if ($y >= $yend[-1]) {
$n += $f[-1];
$x -= $xend[-1];
$y -= $yend[-1];
### shift to: "$x,$y levelmod ".($level % 6)
if (($level % 6) == 0) { # F6 N=8 etc
($x,$y) = ($y,-$x); # -90
} elsif (($level % 6) == 1) { # F7 N=13 etc
$x = -$x; # -90 T
} elsif (($level % 6) == 2) { # F8 N=21 etc, incl F2 N=1
($x,$y) = ($y,$x); # T
}
### rot to: "$x,$y"
if ($x < 0 || $y < 0) {
return undef;
}
}
}
pop @f;
pop @xend;
pop @yend;
$level--;
}
if ($x != 0 || $y != 0) {
return undef;
}
return $n;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### FibonacciWordKnott rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
### rect_to_n_range(): "$x1,$y1 to $x2,$y2"
if ($x2 < 0 || $y2 < 0) {
return (1, 0);
}
foreach ($x1,$x2,$y1,$y2) {
if (is_infinite($_)) { return (0, $_); }
}
my $zero = ($x1 * 0 * $y1 * $x2 * $y2); # inherit bignum 0
my $one = $zero + 1; # inherit bignum 0
my $f0 = 1;
my $f1 = 2;
my $xend0 = $zero;
my $xend1 = $one;
my $yend0 = $one;
my $yend1 = $one;
my $level = 3;
for (;;) {
my ($xo,$yo);
if (($level % 6) == 3) { # at F3 N=2 etc
$xo = $yend0; # -90
$yo = - $xend0;
} elsif (($level % 6) == 4) { # at F4 N=3 etc
$xo = $xend0; # T -90
$yo = - $yend0;
} elsif (($level % 6) == 5) { # at F5 N=5 etc
$xo = $yend0; # T
$yo = $xend0;
} elsif (($level % 6) == 0) { # at F6 N=8 etc
$xo = - $yend0; # +90
$yo = $xend0;
} elsif (($level % 6) == 1) { # at F7 N=13 etc
$xo = - $xend0; # T +90
$yo = $yend0;
} else { # if (($level % 6) == 2) { # at F8 N=21 etc
$xo = $yend0; # T
$yo = $xend0;
}
($f1,$f0) = ($f1+$f0,$f1);
($xend1,$xend0) = ($xend1+$xo,$xend1);
($yend1,$yend0) = ($yend1+$yo,$yend1);
$level++;
### consider: "f1=$f1 xy end $xend1,$yend1"
if ($xend1 > $x2 && $yend1 > $y2) {
return (0, $f1 - 1);
}
}
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/SumFractions.pm 0000644 0001750 0001750 00000007167 12251673621 021304 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::SumFractions;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::NumSeq::BalancedBinary;
# uncomment this to run the ### lines
# use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant xy_is_visited => 1;
sub new {
my $self = shift->SUPER::new (@_);
$self->{'seq'} = Math::NumSeq::BalancedBinary->new;
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### SumFractions n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my $d = int((sqrt(8*$n-7) - 1) / 2);
$n -= $d*($d+1)/2 + 1;
### $d
### $n
return _dn_to_xy($d,$n);
}
sub _dn_to_xy {
my ($d,$n) = @_;
if ($n == 0) { return (1,1); }
if ($n == $d) { return (1,$d+1) };
return _rat_sum(_dn_to_xy($d-1,$n),
_dn_to_xy($d-1,$n-1));
}
sub _rat_sum {
my ($x1,$y1, $x2,$y2) = @_;
my $num = $x1*$y2 + $x2*$y1;
my $den = $y1*$y2;
my $gcd = Math::PlanePath::GcdRationals::_gcd($num,$den);
return ($num/$gcd, $den/$gcd);
}
use Math::PlanePath::GcdRationals;
*_gcd = \&Math::PlanePath::GcdRationals::_gcd;
sub xy_to_n {
my ($self, $x, $y) = @_;
### SumFractions xy_to_n(): "$x, $y"
return undef;
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
my $zero = $x * 0 * $y;
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
my $value = $self->{'seq'}->ith($y) || 0;
### value at y: $value
my $pow = (4+$zero)**$x;
$value *= $pow;
$value += 2*($pow-1)/3;
### mul: sprintf '%#b', $pow
### add: sprintf '%#b', 2*($pow-1)/3
### value: sprintf '%#b', $value
### $value
### value: ref $value && $value->as_bin
return $self->{'seq'}->value_to_i($value);
}
# exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### SumFractions rect_to_n_range(): "$x1,$y1 $x2,$y2"
return (1,10000);
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
# bottom left into first quadrant
if ($x1 < 0) { $x1 *= 0; }
if ($y1 < 0) { $y1 *= 0; }
return (0,
4**($x2+$y2));
return ($self->xy_to_n($x1,$y1), # bottom left
$self->xy_to_n($x2,$y2)); # top right
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/MooreSpiral.pm 0000644 0001750 0001750 00000042416 12250720133 021105 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=MooreSpiral --all --output=numbers_dash
# math-image --path=MooreSpiral,arms=2 --all --output=numbers_dash
# www.nahee.com/spanky/www/fractint/lsys/variations.html
# William McWorter mcworter@midohio.net
# http://www.nahee.com/spanky/www/fractint/lsys/moore.gif
package Math::PlanePath::MooreSpiral;
use 5.004;
use strict;
use List::Util 'min'; # 'max'
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant parameter_info_array => [ { name => 'arms',
share_key => 'arms_2',
display => 'Arms',
type => 'integer',
minimum => 1,
maximum => 2,
default => 1,
width => 1,
description => 'Arms',
} ];
sub new {
my $self = shift->SUPER::new(@_);
$self->{'arms'} = max(1, min(2, $self->{'arms'} || 1));
return $self;
}
my @next_state = (20,30, 0, 60, 0,10, 70,60,50, undef, # 0
30, 0, 10,70,10, 20,40,70, 60,undef, # 10
0, 10,20,40, 20,30,50, 40,70,undef, # 20
10,20,30, 50,30, 0, 60,50,40, undef, # 30
10,20, 30,50,40, 20,40,70, 60,undef, # 40
20, 30, 0,60, 50,30,50, 40,70,undef, # 50
30, 0,10, 70,60, 0, 60,50,40, undef, # 60
0,10, 20,40,70, 10,70,60, 50,undef); # 70
my @digit_to_x = ( 0, 1, 1, 0,-1,-2, -2,-2,-3, -3, # 0
0, 0, -1,-1,-1, -1, 0, 1, 1, 0, # 10
0, -1,-1, 0, 1, 2, 2, 2, 3, 3, # 20
0, 0, 1, 1, 1, 1, 0,-1,-1, 0, # 30
0, 0, 1, 1, 1, 2, 3, 4, 4, 3, # 40
0, 1, 1, 0, -1,-1,-1, -1, 0, 0, # 50
0, 0,-1, -1,-1,-2, -3,-4,-4, -3, # 60
0,-1, -1, 0, 1, 1, 1, 1, 0, 0); # 70
my @digit_to_y = ( 0, 0, 1, 1, 1, 1, 0,-1,-1, 0, # 0
0, 1, 1, 0,-1, -2,-2,-2, -3,-3, # 10
0, 0,-1,-1, -1,-1, 0, 1, 1, 0, # 20
0,-1,-1, 0, 1, 2, 2, 2, 3, 3, # 30
0,-1, -1, 0, 1, 1, 1, 1, 0, 0, # 40
0, 0, 1, 1, 1, 2, 3, 4, 4, 3, # 50
0, 1, 1, 0,-1,-1, -1,-1, 0, 0, # 60
0, 0, -1,-1,-1, -2,-3,-4, -4,-3); # 70
# state length 80 in each of 4 tables
# rot2 state 20
sub n_to_xy {
my ($self, $n) = @_;
### MooreSpiral n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
my $int = int($n);
$n -= $int; # frac
# initial state from arm number $int mod $arms
my $state = 20;
my $arms = $self->{'arms'};
if ($arms > 1) {
my $arm = _divrem_mutate($int,2);
if ($arm) {
$state = 0;
$int += 1;
}
}
my @digits = digit_split_lowtohigh($int,9);
my $zero = $int*0; # inherit bignum 0
my $len = ($zero+3) ** scalar(@digits);
unless ($#digits & 1) {
$state ^= 20; # rot 18re0
}
### digits: join(', ',@digits)." count ".scalar(@digits)
### $len
### initial state: $state
my $x = 0;
my $y = 0;
my $dir = 0;
while (@digits) {
$len /= 3;
### at: "$x,$y"
### $len
### digit: $digits[-1]
### state: $state
# . " ".state_string($state)
$state += (my $digit = pop @digits);
if ($digit != 8) {
}
$dir = $state; # lowest non-zero digit
### digit_to_x: $digit_to_x[$state]
### digit_to_y: $digit_to_y[$state]
### next_state: $next_state[$state]
$x += $len * $digit_to_x[$state];
$y += $len * $digit_to_y[$state];
$state = $next_state[$state];
}
### final: "$x,$y"
# with $n fractional part
return ($n * ($digit_to_x[$dir+1] - $digit_to_x[$dir]) + $x,
$n * ($digit_to_y[$dir+1] - $digit_to_y[$dir]) + $y);
}
# 61-62 67-68-69-70 4
# | | | |
# 60 63 66 73-72-71 3
# | | | |
# 59 64-65 74-75-76 2
# | |
# 11-10 5--4--3--2 58-57-56 83-82 77 1
# | | | | | | | |
# 12 9 6 0--1 53-54-55 84 81 78 <- Y=0
# | | | | | | |
# 13 8--7 52-51-50 85 80-79 -1
# | | |
# 14-15-16 25-26 31-32-33-34 43-44 49 86-87-88 97-98 -2
# | | | | | | | | | | |
# 19-18-17 24 27 30 37-36-35 42 45 48 91-90-89 96 99 -3
# | | | | | | | | | | |
# 20-21-22-23 28-29 38-39-40-41 46-47 92-93-94-95 ... -4
# 40 -3*9 = 40-27=13
# 13 -8 = 5
#
# bottom right corner "40" N=(9^level-1)/2
# bottom left corner "20"
# N=(9^level-1)/2 - 3*3^level
# len=3 Nr=(9*len*len-1)/2=40
# Nl=Nr - 2*len*len - (len-1)
# = (9*len*len-1)/2 - 2*len*len - (len-1)
# = (9*len*len-1 - 4*len*len - 2*(len-1))/2
# = (9*len*len - 1 - 4*len*len - 2*len + 2)/2
# = (5*len*len - 2*len + 1)/2
# = ((5*len - 2)*len + 1)/2
#
# round 2,5,etc 1+(3^level-1)/2 = x
# 2*(x-1) = 3^level-1
# 3^level = 2x-2+1 = 2x-1
# offset 1,4,etc 1+...+3^(level-1) = (3^level-1)/2
#
my @yx_to_rot = (0,3,0, # y=0
1,2,1, # y=1
0,3,0); # y=2
my @yx_to_digit = (-2,-3,-4, # y=0
-1,0,1, # y=1
4,3,2); # y=2
sub xy_to_n {
my ($self, $x, $y) = @_;
### MooreSpiral xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
my ($len, $level) = round_down_pow (max(abs($x),abs($y))*2 - 1,
3);
### $len
### $level
# offset to make bottom left corner X=0,Y=0
{
my $offset = (3*$len-1)/2;
$x += $offset;
$y += $offset;
### $offset
### offset to: "$x,$y"
### assert: $x >= 0
### assert: $y >= 0
### assert: $x < 3*$len
### assert: $y < 3*$len
}
if (is_infinite($x)) {
return $x;
}
if (is_infinite($y)) {
return $y;
}
my $arms = $self->{'arms'};
my $npow = $len*$len;
my $n = ($x * 0 * $y); # + (9*$npow - 1)/2;
my $rot = ($level & 1 ? 2 : 0);
my @x = digit_split_lowtohigh ($x, 3);
my @y = digit_split_lowtohigh ($y, 3);
### @x
### @y
for ( ; $level >= 0; $level--) {
### $n
### $rot
$x = $x[$level] || 0;
$y = $y[$level] || 0;
### raw xy digits: "$x,$y"
if ($rot&1) {
($x,$y) = (2-$y,$x) # rotate +90
}
if ($rot&2) {
$x = 2-$x; # rotate 180
$y = 2-$y;
}
### rotated xy digits: "$x,$y"
my $k = $y*3+$x;
$rot += $yx_to_rot[$k];
my $digit = $yx_to_digit[$k];
$n += $npow*$digit;
### $digit
### add to n: $npow*$digit
if ($n < 0 && $self->{'arms'} < 2) {
### negative when only 1 arm ...
return undef;
}
$npow /= 9;
}
### final n: $n
if ($arms < 2) {
return $n;
}
if ($n < 0) {
return -1-2*$n;
} else {
return 2*$n;
}
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### MooreSpiral rect_to_n_range(): "$x1,$y1, $x2,$y2"
$x1 = round_nearest ($x1);
$x2 = round_nearest ($x2);
$y1 = round_nearest ($y1);
$y2 = round_nearest ($y2);
my ($len, $level) = round_down_pow (max(abs($x1),abs($y1),
abs($x2),abs($y2))*2-1,
3);
### $len
### $level
return (0,
($x1 * 0 * $y1 * $x2 * $y2)
+ (9*$len*$len - 1) * $self->{'arms'} / 2);
}
1;
__END__
=for stopwords eg Ryde ie MooreSpiral Math-PlanePath Moore
=head1 NAME
Math::PlanePath::MooreSpiral -- 9-segment self-similar spiral
=head1 SYNOPSIS
use Math::PlanePath::MooreSpiral;
my $path = Math::PlanePath::MooreSpiral->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
This is an integer version of a 9-segment self-similar curve by ...
61-62 67-68-69-70 4
| | | |
60 63 66 73-72-71 3
| | | |
59 64-65 74-75-76 2
| |
11-10 5--4--3--2 58-57-56 83-82 77 1
| | | | | | | |
12 9 6 0--1 53-54-55 84 81 78 <- Y=0
| | | | | | |
13 8--7 52-51-50 85 80-79 -1
| | |
14-15-16 25-26 31-32-33-34 43-44 49 86-87-88 97-98 -2
| | | | | | | | | | |
19-18-17 24 27 30 37-36-35 42 45 48 91-90-89 96 99 -3
| | | | | | | | | | |
20-21-22-23 28-29 38-39-40-41 46-47 92-93-94-95 ... -4
-4 -3 -2 -1 X=0 1 2 3 4 5 6 7 8 9 10 11 12
The base pattern is the N=0 to N=9 shape. Then there's 9 copies of that
shape in the same relative directions as those segments and with reversals
in the 3,6,7,8 parts. The first reversed section is N=3*9=27 to N=4*9=36.
rev
5------4------3------2
| |
| |
9 6 0------1
| |rev
rev| |
8------7
rev
Notice the points N=9,18,27,...,81 are the base shape rotated 180 degrees.
Likewise for N=81,162,etc and any multiples of N=9^level, with each
successive level being rotated 180 degrees relative to the preceding. The
effect is to spiral around with an ever fatter 3^level width,
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
*************************** *********
*************************** *********
*************************** *********
*************************** ****** *********
*************************** *** ** *********
*************************** *** *********
*************************** ******************
*************************** ******************
*************************** ******************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
=head2 Arms
The optional C 2> parameter can give a second copy of the spiral
rotated 180 degrees. With two arms all points of the plane are covered.
93--91 81--79--77--75 57--55 45--43--41--39 122-124 ..
| | | | | | | | | | |
95 89 83 69--71--73 59 53 47 33--35--37 120 126 132
| | | | | | | | | | |
97 87--85 67--65--63--61 51--49 31--29--27 118 128-130
| | |
99-101-103 22--20 10-- 8-- 6-- 4 13--15 25 116-114-112
| | | | | | | | |
109-107-105 24 18 12 1 0-- 2 11 17 23 106-108-110
| | | | | | | | |
111-113-115 26 16--14 3-- 5-- 7-- 9 19--21 104-102-100
| | |
129-127 117 28--30--32 50--52 62--64--66--68 86--88 98
| | | | | | | | | | |
131 125 119 38--36--34 48 54 60 74--72--70 84 90 96
| | | | | | | | | | |
.. 123-121 40--42--44--46 56--58 76--78--80--82 92--94
The first arm is the even numbers N=0,2,4,etc and the second arm is the odd
numbers N=1,3,5,etc.
=head2 Wunderlich Serpentine Curve
The way the ends join makes little "S" shapes similar to the PeanoCurve.
The first is at N=5 to N=13,
11-10 5
| | |
12 9 6
| | |
13 8--7
The wider parts then have these sections alternately horizontal or vertical
in the style of Walter Wunderlich's "serpentine" type 010 101 010 curve.
For example the 9x9 block N=41 to N=101,
61--62 67--68--69--70 115-116 121
| | | | | | |
60 63 66 73--72--71 114 117 120
| | | | | | |
59 64--65 74--75--76 113 118-119
| | |
58--57--56 83--82 77 112-111-110
| | | | |
53--54--55 84 81 78 107-108-109
| | | | |
52--51--50 85 80--79 106-105-104
| | |
43--44 49 86--87--88 97--98 103
| | | | | | |
42 45 48 91--90--89 96 99 102
| | | | | | |
41 46--47 92--93--94--95 100-101
The whole curve is in fact like the Wunderlich serpentine started from the
middle. This can be seen in the two arms picture above (in mirror image of
the usual PlanePath start direction for Wunderlich's curve).
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::MooreSpiral-Enew ()>
Create and return a new path object.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
=back
=head1 FORMULAS
=head2 X,Y to N
The correspondence to Wunderlich's 3x3 serpentine curve can be used to turn
X,Y coordinates in base 3 into an N. Reckoning the innermost 3x3 as level=1
then the smallest abs(X) or abs(Y) in a level is
Xlevelmin = (3^level + 1) / 2
eg. level=2 Xlevelmin=5
which can be reversed as
level = log3floor( max(abs(X),abs(Y)) * 2 - 1 )
eg. X=7 level=log3floor(2*7-1)=2
An offset can be applied to put X,Y in the range 0 to 3^level-1,
offset = (3^level-1)/2
eg. level=2 offset=4
Then a table can give the N base-9 digit corresponding to X,Y digits
Y=2 4 3 2 N digit
Y=1 -1 0 1
Y=0 -2 -3 -4
X=0 X=1 X=2
A current rotation maintains the "S" part directions and is updated by a
table
Y=2 0 +3 0 rotation when descending
Y=1 +1 +2 +1 into sub-part
Y=0 0 +3 0
X=0 X=1 X=2
The negative digits of N represent backing up a little in some higher part.
If N goes negative at any state then X,Y was off the main curve and instead
on the second arm. If the second arm is not of interest the calculation can
stop at that stage.
It no doubt would also work to take take X,Y as balanced ternary digits
1,0,-1, but it's not clear that would be any faster or easier to calculate.
=head1 SEE ALSO
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffLines.pm 0000644 0001750 0001750 00000025672 12250720133 021277 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# x=45,y=10 x=59,y=19 dx=14,dy=9 14/9=1.55
#
# x=42,y=8 x=113,y=52 dx=71,dy=44 71/44=1.613
#
# below
# 32,12 to 36,4 sqrt((32-36)^2+(12-4)^2) = 9
# 84,34 to 99,14 sqrt((84-99)^2+(34-14)^2) = 25
# 180,64 to 216,11 sqrt((180-216)^2+(64-11)^2) = 64
#
# above
# 14,20 to 5,32 sqrt((14-5)^2+(20-32)^2) = 15 = 9*1.618 3
# 34,50 to 14,85 sqrt((34-14)^2+(50-85)^2) = 40 = 25*1.618 5
# 132,158 to 77,247 sqrt((132-77)^2+(158-247)^2) = 104 = 64*1.618 8
# 8,525 to 133,280 sqrt((8-133)^2+(525-280)^2) = 275 = 169*1.618 13
package Math::PlanePath::WythoffLines;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'bit_split_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant parameter_info_array =>
[ { name => 'shift',
display => 'Shift',
type => 'integer',
default => 0,
width => 3,
},
];
# shift x_minimum() y_minimum()
# -4 13 8
# -3 8 5
# -2 5 3
# -1 3 2
# 1 2 1
# 0 2 1 ...
# 1 1 1 fib(1)
# 2 1 /---> 0 -----^ fib(0)
# 3 0 <--/ 1 a
# 4 1 -1 b
# 5 -1 2 c
# 6 2 -4 d -4=2*-1-2
# 7 -4 4 e 4=2*2-0
# 8 4 -12 -12=2*-4-4
# 9 -12 9 9=2*4-(-1)
# 10 9 -33
# 11 -33 22 22=3*9-4-1 a(n)=3a(n-2)-a(n-4)-1
# 12 22 -88 -88=2*-33-22 2*a(n-2)-a(n-1)
# 13 -88 56 56=2*22+12 2*a(n-2)-a(n-5)
# 14 56 -232 -232=2*-88-56 2*a(n-2)-a(n-1)
# 15 -232 145 145=2*56+33 2*a(n-2)-a(n-5)
# 16 -609 -609=2*-232-145
# 17 -609 378 378=2*145-(-88)
#
# shift -4,-12,-33,-88,-232 = 1-Fib(2*s+1)
# shift 9,22,56,145,378,988
# a(n)=3*a(n-1)-a(n-2)-1
# with $shift reckoned for y_minimum()
sub _calc_minimum {
my ($shift) = @_;
if ($shift <= 2) {
return _fibonacci(2-$shift);
}
if ($shift & 1) {
# shift odd >= 3, so (shift-1)/2 >= 1
my $a = 1;
my $b = 2;
foreach (2 .. ($shift-1)/2) {
($a,$b) = ($b, 3*$b-$a-1);
}
return $a;
} else {
# shift even >= 4
return 1 - _fibonacci($shift-1);
}
# $a = 1;
# $b = -1;
# my $c = 2;
# my $d = -4;
# my $e = 4;
# for (my $i = 2; $i < $shift; $i++) {
# ($a,$b,$c,$d,$e) = ($b,$c,$d,$e, 2*$d-$e);
# $i++;
# last unless $i < $shift;
# ($a,$b,$c,$d,$e) = ($b,$c,$d,$e, 2*$d-$a);
# }
# return $a;
}
sub _fibonacci {
my ($n) = @_;
$a = 0;
$b = 1;
foreach (1 .. $n) {
($a,$b) = ($b,$a+$b);
}
return $a;
}
sub x_minimum {
my ($self) = @_;
return _calc_minimum($self->{'shift'}-1);
}
sub y_minimum {
my ($self) = @_;
return _calc_minimum($self->{'shift'});
}
#------------------------------------------------------------------------------
use Math::PlanePath::WythoffArray;
my $wythoff = Math::PlanePath::WythoffArray->new;
sub new {
my $self = shift->SUPER::new(@_);
$self->{'shift'} ||= 0;
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### WythoffLines n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# $n -= 1;
# my $y = $wythoff->xy_to_n(0,$n);
# my $x = $wythoff->xy_to_n(1,$n);
# 1 2.000, 1.000 1 1_100000 5.000,3.000(5.831)
# 2 7.000, 4.000 2 1_100000 3.000,2.000(3.606)
# 3 10.000, 6.000 3 1_100000 5.000,3.000(5.831)
# 4 15.000, 9.000 4 1_100000 5.000,3.000(5.831)
# 5 20.000, 12.000 5 1_100000 3.000,2.000(3.606)
# 6 23.000, 14.000 6 1_100000 5.000,3.000(5.831)
# 7 28.000, 17.000 7 1_100000 3.000,2.000(3.606)
my $zero = $n*0;
# spectrum(Y+1) so Y,Ybefore are notional two values at X=-2 and X=-1
my $y = $n-1;
my $x = int((sqrt(5*$n*$n) + $n) / 2);
# ($y,$x) = (1*$x + 1*$y,
# 2*$x + 1*$y);
# shift s to -1
# 1 to s
# but forward by 2 extra
# s to -1+2=1
# 1+2=3 to s
foreach ($self->{'shift'} .. 1) {
($y,$x) = ($x,$x+$y);
}
foreach (3 .. $self->{'shift'}) {
# prev+y=x
# prev = x-y
($y,$x) = ($x-$y,$y);
}
return ($x,$y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### WythoffLines xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
# if (is_infinite($y)) { return $y; }
# unshift
#
foreach ($self->{'shift'} .. -1) {
($y,$x) = ($x-$y,$y);
}
foreach (1 .. $self->{'shift'}) {
($y,$x) = ($x,$x+$y);
}
### unshifted to: "$x,$y"
if (my ($cy,$ny) = $wythoff->n_to_xy($y)) {
### y: "cy=$cy ny=$ny"
if ($cy == 0) {
if (my ($cx,$nx) = $wythoff->n_to_xy($x)) {
if ($cx == 1 && $nx == $ny) {
return $nx+1;
}
}
}
}
return undef;
# my $y = $wythoff->xy_to_n(0,$n);
# my $x = $wythoff->xy_to_n(1,$n);
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### WythoffLines rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $zero = $x1 * 0 * $y1 * $x2 * $y2;
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
# FIXME: probably not quite right
my $phi = (1 + sqrt(5+$zero)) / 2;
return (1,
max (1,
int($phi**($self->{'shift'}-2)
* max ($x1,$x2, max($y1,$y2)*$phi))));
}
1;
__END__
=for stopwords eg Ryde Math-PlanePath Moore Wythoff Zeckendorf concecutive fibbinary OEIS
=head1 NAME
Math::PlanePath::WythoffLines -- table of Fibonacci recurrences
=head1 SYNOPSIS
use Math::PlanePath::WythoffLines;
my $path = Math::PlanePath::WythoffLines->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
XThis path is the Wythoff preliminary triangle by Clark
Kimberling,
=cut
# math-image --path=WythoffLines --output=numbers --all --size=60x14
=pod
13 | 105 118 131 144 60 65 70 75 80 85 90 95 100
12 | 97 110 47 52 57 62 67 72 77 82 87 92
11 | 34 39 44 49 54 59 64 69 74 79 84
10 | 31 36 41 46 51 56 61 66 71 76
9 | 28 33 38 43 48 53 58 63 26
8 | 25 30 35 40 45 50 55 23
7 | 22 27 32 37 42 18 20
6 | 19 24 29 13 15 17
5 | 16 21 10 12 14
4 | 5 7 9 11
3 | 4 6 8
2 | 3 2
1 | 1
Y=0 |
+-----------------------------------------------------
X=0 1 2 3 4 5 6 7 8 9 10 11 12
A coordinate pair Y and X are the start of a Fibonacci style recurrence,
F[1]=Y, F[2]=X F[i+i] = F[i] + F[i-1]
Any such sequence eventually becomes a row of the Wythoff array
(L) after some number of initial iterations.
The N value at X,Y is the row number of the Wythoff array containing
sequence beginning Y and X. Rows are numbered starting from 1. Eg.
Y=4,X=1 sequence: 4, 1, 5, 6, 11, 17, 28, 45, ...
row 7 of WythoffArray: 17, 28, 45, ...
so N=7 at Y=4,X=1
Conversely a given N is positioned in the triangle according to where row
number N of the Wythoff array "precurses" by running the recurrence in
reverse,
F[i-1] = F[i+i] - F[i]
It can be shown that such a precurse always reaches a pair Y and X with
YE=1 and 0E=XEY, hence making the triangular X,Y arrangement
above.
N=7 WythoffArray row 7 is 17,28,45,73,...
go backwards from 17,28 by subtraction
11 = 28 - 17
6 = 17 - 11
5 = 11 - 6
1 = 6 - 5
4 = 5 - 1
stop on reaching 4,1 which is Y=4,X=1 satisfying Y>=1 and 0<=X=XEY
=cut
# (r-1 + floor(r*phi)) / (r-1 + 2*floor(r*phi))
# ~= (r-1+r*phi)/(r-1+2*r*phi)
# = (r*(phi+1) - 1) / (r*(2phi+1) - 1)
# -> r*(phi+1) / r*(2*phi+1)
# = (phi+1) / (2*phi+1)
# = 1/phi = 0.618
=pod
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::WythoffLines-Enew ()>
Create and return a new path object.
=back
=head1 OEIS
The Wythoff array is in Sloane's Online Encyclopedia of Integer Sequences
in various forms,
=over
L (etc)
=back
A165360 X
A165359 Y
A166309 N by rows
=head1 SEE ALSO
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/BinaryTerms-oeis.t 0000644 0001750 0001750 00000006634 12132055333 021700 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
MyTestHelpers::nowarnings();
use MyOEIS;
use Math::PlanePath::BinaryTerms;
{
require Math::BaseCnv;
my $radix = 3;
my $path = Math::PlanePath::BinaryTerms->new (radix => $radix);
foreach my $y ($path->y_minimum .. 8) {
printf '%2d', $y;
foreach my $x ($path->x_minimum .. 7) {
my $n = $path->xy_to_n($x,$y);
my $nr = Math::BaseCnv::cnv($n,10,$radix);
printf " %10s", $nr;
}
print "\n";
}
}
#------------------------------------------------------------------------------
# A068076 X = num integers 'A068076',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::BinaryTerms->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x-1;
}
return \@got;
});
#------------------------------------------------------------------------------
# A067576 binary by anti-diagonals upwards
MyOEIS::compare_values
(anum => 'A067576',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::BinaryTerms->new (radix => 2);
my $diag = Math::PlanePath::Diagonals->new (direction => 'up',
x_start=>1,y_start=>1);
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A066884 binary diagonals downwards
MyOEIS::compare_values
(anum => 'A066884',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::BinaryTerms->new;
my $diag = Math::PlanePath::Diagonals->new (x_start=>1,y_start=>1);
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
# A067587 inverse
MyOEIS::compare_values
(anum => 'A067587',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::BinaryTerms->new;
my $diag = Math::PlanePath::Diagonals->new (x_start=>1,y_start=>1);
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $diag->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/devel/lib/Math/PlanePath/BinaryTerms.pm 0000644 0001750 0001750 00000022751 12250720133 021110 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# cf A134562 base-3 Y=sum digits
# http://cut-the-knot.org/wiki-math/index.php?n=Probability.ComboPlayground
# combinations
# row
# Y=1 2^k
# Y=2 2-bit numbers
# column
# X=1 first with Y many bits is Zeck 11111
# A027941 Fib(2n+1)-1
# X=2 second with Y many bits is Zeck 101111 high 1, low 1111
# A005592 F(2n+1)+F(2n-1)-1
# X=3 third with Y many bits is Zeck 110111
# A005592 F(2n+1)+F(2n-1)-1
# X=4 fourth with Y many bits is Zeck 111011
# 111101
# 111110
# 1001111
# 1010111
# 1011011
# 1011101
# 1011110
# 1100111
# 1101011
# 1101101
# 1101110
# 1110011
# 1110101
# 1110110
# 1111001
# 1111010
# 1111100
# 15 binomial(6,4)=15
#
# binomial(a,b) = a! / (b! * (a-b!))
#
# binomial(X-1,X-1) 4,4
# binomial(X, X-1) 5,4
# binomial(X+1,X-1) 5,4
# bin(a+1,b) = (a+1)!/(b! * (a+1-b)!)
# bin(a+1,b) = a!/(b! * (a-b)!) * (a+1)/(a+1-b)
# bin(a+1,b) = bin(a,b) * (a+1)/(a+1-b)
#
# bin(a,b+1) = (a)!/((b+1)! * (a-b-1)!)
# bin(a,b+1) = (a)!/(b! * (a-b)!) * (b+1)*(a-b)
# bin(a,b+1) = bin(a,b) * (b+1)*(a-b)
#
# bin(a-1,b) = (a-1)! / (b! * (a-1-b)!)
# bin(a-1,b) = a! / (b! * (a-b)!) ( (a-b)/a
# bin(a-1,b) = bin(a,b) * (a-b)/a
# bin(a,b-1) = a!/((b-1)! * (a-b+1)!)
# bin(a,b-1) = a!/(b! * (a-b)!) * b/(a-b+1)
# bin(a,b-1) = bin(a,b) * b/(a-b+1)
#
#
# 1 2 3 4 5 6
# Y=2 11 101 110 1001 1010 1100
# 3 5 6 9 10 12
# 1 \------2 \-------------3
# 1 2 3 4 5 6
# Y=3 111 1011 1101 1110
# 3 11 13 14
# 1 \-------------3 \-------------
# 1 2 3 4 5 6
# Y=4 111 1011 1101 1110
# 3 11 13 14
# 1 \-------------3 \-------------
package Math::PlanePath::BinaryTerms;
use 5.004;
use strict;
use List::Util 'sum';
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem = \&Math::PlanePath::_divrem;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh',
'digit_join_lowtohigh';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant parameter_info_array =>
[ Math::PlanePath::Base::Digits::parameter_info_radix2(),
];
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant y_minimum => 1;
use constant x_minimum => 1;
#------------------------------------------------------------------------------
my $global_radix = 0;
my $next_n = 1;
my @n_to_x;
my @n_to_y;
my @yx_to_n;
sub new {
my $self = shift->SUPER::new(@_);
$self->{'radix'} ||= 2;
if ($global_radix != $self->{'radix'}) {
$global_radix = $self->{'radix'};
$next_n = 1;
@n_to_x = ();
@n_to_y = ();
@yx_to_n = ();
}
return $self;
}
sub _extend {
my ($self) = @_;
### _extend() ...
### $next_n
my $n = $next_n++;
my @ndigits = digit_split_lowtohigh($n,$self->{'radix'});
### ndigits low to high: join(',',@ndigits)
my $y = 0;
foreach (@ndigits) {
if ($_) { $y++; }
}
my $row = ($yx_to_n[$y] ||= []);
my $x = scalar(@$row) || 1;
$row->[$x] = $n;
$n_to_x[$n] = $x;
$n_to_y[$n] = $y;
### push: "x=$x y=$y n=$n"
### @yx_to_n
}
sub n_to_xy {
my ($self, $n) = @_;
### BinaryTerms n_to_xy(): "$n radix=$self->{'radix'}"
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my $radix = $self->{'radix'};
if ($radix > 2) {
while ($next_n <= $n) {
_extend($self);
}
return ($n_to_x[$n], $n_to_y[$n]);
}
{
my @ndigits = digit_split_lowtohigh($n,$radix);
pop @ndigits; # drop high 1-bit
my $ones = sum(0,@ndigits);
my $y = $ones + 1;
### $y
### ndigits low to high: join(',',@ndigits)
### $ones
my $binomial
= my $x
= $n * 0 + 1; # inherit bignum 1
for (my $len = $ones; $len <= $#ndigits; ) {
### block add to x: $binomial
$x += $binomial * ($radix-1)**$ones;
# bin(a+1,b) = bin(a,b) * (a+1)/(a+1-b)
$len++;
$binomial *= $len;
### assert: $binomial % ($len-$ones) == 0
$binomial /= ($len-$ones);
### assert: $binomial == _binomial($len,$ones)
}
# here $binomial = binomial(len,ones)
my $len = scalar(@ndigits);
foreach my $digit (reverse @ndigits) { # high to low
### digit: "$digit len=$len ones=$ones binomial=$binomial x=$x"
if ($len == $ones || $ones == 0) {
last;
}
# bin(a-1,b) = bin(a,b) * (a-b)/a
$binomial *= ($len-$ones);
### assert: $binomial % $len == 0
$binomial /= $len;
$len--;
### decr len to: "len=$len ones=$ones binomial=$binomial"
### assert: $binomial == _binomial($len,$ones)
if ($digit) {
### add to x: $binomial
$x += $binomial * $digit * ($radix-1)**$ones;
# bin(a,b-1) = bin(a,b) * b/(a-b+1)
### assert: ($binomial * $ones) % ($len-$ones+1) == 0
$binomial *= $ones;
$ones--;
$binomial /= ($len-$ones);
### assert: $binomial == _binomial($len,$ones)
}
}
### result: "x=$x ones=$ones"
return ($x, $y);
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### BinaryTerms xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
my $radix = $self->{'radix'};
if ($radix > 2) {
if ($x < 1 || $y < 1) { return undef; }
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
for (;;) {
if (defined (my $n = $yx_to_n[$y][$x])) {
return $n;
}
_extend($self);
}
}
{
$x -= 1;
if ($x < 0 || $y < 1) { return undef; }
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
my $len = my $ones = $y-1;
my $binomial = 1;
while ($x >= $binomial * ($radix-1)**$ones) {
### subtract high from: "len=$len ones=$ones binomial=$binomial x=$x"
$x -= $binomial;
# bin(a+1,b) = bin(a,b) * (a+1)/(a+1-b)
$len++;
$binomial *= $len;
### assert: $binomial % ($len-$ones) == 0
$binomial /= ($len-$ones);
### assert: $binomial == _binomial($len,$ones)
}
### found high: "len=$len ones=$ones binomial=$binomial x=$x"
my @ndigits = (1); # high to low
while ($len > 0) {
### at: "len=$len ones=$ones binomial=$binomial x=$x"
### assert: $len >= $ones
if ($len == $ones) {
push @ndigits, (1) x $ones;
last;
}
if ($ones == 0) {
push @ndigits, (0) x $len;
last;
}
# bin(a-1,b) = bin(a,b) * (a-b)/a
$binomial *= ($len-$ones);
### assert: $binomial % $len == 0
$binomial /= $len;
$len--;
### decr len to: "len=$len ones=$ones binomial=$binomial"
### assert: $binomial == _binomial($len,$ones)
my $bcmp = $binomial * ($radix-1)**$ones;
### compare: "x=$x bcmp=$bcmp"
if ($x >= $bcmp) {
### yes, above, push digit ...
# (my $digit, $x) = _divrem($x,$bcmp);
# push @ndigits, $digit;
# ### assert: $digit >= 1
# ### assert: $digit < $radix
$x -= $binomial * ($radix-1)**$ones;
push @ndigits, 1;
# bin(a,b-1) = bin(a,b) * b/(a-b+1)
$binomial *= $ones;
$ones--;
### assert: ($binomial * $ones) % ($len-$ones) == 0
$binomial /= $len-$ones;
### assert: $binomial == _binomial($len,$ones)
} else {
### no, push 0 digit ...
push @ndigits, 0;
}
}
### ndigits: join(',',@ndigits)
@ndigits = reverse @ndigits;
return digit_join_lowtohigh(\@ndigits,$radix, $x*0*$y);
}
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### BinaryTerms rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 1 || $y2 < 1) { return (1,0); }
return (1, max($self->xy_to_n($x2,$y2),
$self->xy_to_n($x2,1)));
return (1, 10000);
}
sub _binomial {
my ($a,$b) = @_;
$a >= $b or die "_binomial($a,$b)";
my $ret = 1;
foreach (2 .. $a) { $ret *= $_ }
foreach (2 .. $b) { $ret /= $_ }
foreach (2 .. $a-$b) { $ret /= $_ }
### _binomial: "a=$a b=$b binomial=$ret"
return $ret;
}
1;
__END__
=cut
# math-image --path=BinaryTerms --output=numbers --all --size=60x14
=pod
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffTriangle.pm 0000644 0001750 0001750 00000005630 12251673621 021774 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::WythoffTriangle;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant y_minimum => 1;
use constant xy_is_visited => 1;
use Math::PlanePath::WythoffPreliminaryTriangle;
my $preliminary = Math::PlanePath::WythoffPreliminaryTriangle->new;
sub n_to_xy {
my ($self, $n) = @_;
### WythoffTriangle n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my ($x,$y) = $preliminary->n_to_xy($n) or return;
$x = 0;
foreach my $x2 (0 .. $y-1) {
my $n2 = $preliminary->xy_to_n($x2,$y) or return;
### cf: "x2=$x2 n2=$n2"
if ($n2 < $n) {
### is below ...
$x++;
}
}
return ($x, $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### WythoffTriangle xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($y < 1) { return undef; }
if (is_infinite($y)) { return $y; }
unless ($x >= 0 && $x < $y) { return undef; }
my @n = sort {$a<=>$b}
map { $preliminary->xy_to_n($_,$y) }
0 .. $y-1;
return $n[$x];
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### WythoffTriangle rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 1) {
### all outside first quadrant ...
return (1, 0);
}
# bottom left into first quadrant
if ($x1 < 0) { $x1 *= 0; }
if ($y1 < 0) { $y1 *= 0; }
return (1,
$self->xy_to_n(0,2*$y2));
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/QuintetSide.pm 0000644 0001750 0001750 00000016767 12250720133 021121 0 ustar gg gg # mostly works, but any good ?
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=QuintetSide --lines --scale=10
# math-image --path=QuintetSide --output=numbers
package Math::PlanePath::QuintetSide;
use 5.004;
use strict;
use POSIX 'ceil';
use Math::Libm 'hypot';
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA', '@_xend','@_yend';
$VERSION = 113;
use Math::PlanePath 37;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh';
use Math::PlanePath::SacksSpiral;
# uncomment this to run the ### lines
#use Devel::Comments;
use constant n_start => 0;
sub n_to_xy {
my ($self, $n) = @_;
### QuintetSide n_to_xy(): $n
if ($n < 0) {
return;
}
if (is_infinite($n)) {
return ($n,$n);
}
my $x;
my $y = 0;
{ my $int = int($n);
$x = $n - $int;
$n = $int;
}
my $xend = 1;
my $yend = 0;
foreach my $digit (digit_split_lowtohigh($n,3)) {
my $xend_offset = $xend - $yend; # end + end rotated +90
my $yend_offset = $yend + $xend; # being the digit 2 position
### at: "$x,$y"
### $digit
### $xend
### $yend
### $xend_offset
### $yend_offset
if ($digit == 1) {
($x,$y) = (-$y + $xend, # rotate +90
$x + $yend);
} elsif ($digit == 2) {
$x += $xend_offset; # digit 2 offset position
$y += $yend_offset;
}
$xend += $xend_offset; # 2*end + end rotated +90
$yend += $yend_offset;
}
### final: "$x,$y"
return ($x, $y);
}
@_xend = (1);
@_yend = (0);
sub _ends_for_level {
my ($level) = @_;
### $#_xend
if ($#_xend < $level) {
my $x = $_xend[-1];
my $y = $_yend[-1];
do {
($x,$y) = (2*$x - $y, # 2*$x + rotate +90
2*$y + $x); # 2*$y + rotate +90
### _ends_for_level() push: scalar(@_xend)." $x,$y"
# ### assert: "$x,$y" eq join(','__PACKAGE__->n_to_xy(scalar(@xend) ** 3))
push @_xend, $x;
push @_yend, $y;
} while ($#_xend < $level);
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
$x = round_nearest($x);
$y = round_nearest($y);
### QuintetSide xy_to_n(): "$x, $y"
my $r = hypot($x,$y);
my $level = ceil(log($r+1)/log(sqrt(5)));
if (is_infinite($level)) {
return $level;
}
return _xy_to_n_in_level($x,$y,$level);
}
sub _xy_to_n_in_level {
my ($x, $y, $level) = @_;
_ends_for_level($level);
my @pending_n = (0);
my @pending_x = ($x);
my @pending_y = ($y);
my @pending_level = ($level);
while (@pending_n) {
my $n = pop @pending_n;
$x = pop @pending_x;
$y = pop @pending_y;
$level = pop @pending_level;
### consider: "$x,$y n=$n level=$level"
if ($level == 0) {
if ($x == 0 && $y == 0) {
return $n;
}
next;
}
my $xend = $_xend[$level-1];
my $yend = $_yend[$level-1];
if (hypot($x,$y) * (.9/sqrt(5)) > hypot($xend,$yend)) {
### radius out of range: hypot($x,$y)." cf end ".hypot($xend,$yend)
next;
}
$level--;
$n *= 3;
### descend: "end=$xend,$yend"
# digit 0
push @pending_n, $n;
push @pending_x, $x;
push @pending_y, $y;
push @pending_level, $level;
### push: "$x,$y digit=0"
# digit 1
$x -= $xend;
$y -= $yend;
($x,$y) = ($y, -$x); # rotate -90
push @pending_n, $n + 1;
push @pending_x, $x;
push @pending_y, $y;
push @pending_level, $level;
### push: "$x,$y digit=1"
# digit 2
$x -= $xend;
$y -= $yend;
($x,$y) = (-$y, $x); # rotate +90
push @pending_n, $n + 2;
push @pending_x, $x;
push @pending_y, $y;
push @pending_level, $level;
### push: "$x,$y digit=2"
}
return undef;
}
# radius = sqrt(5) ^ level
# log(radius) = level * log(sqrt(5))
# level = log(radius) * 1/log(sqrt(5))
#
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
$y1 *= sqrt(3);
$y2 *= sqrt(3);
my ($r_lo, $r_hi) = Math::PlanePath::SacksSpiral::_rect_to_radius_range
($x1,$y1, $x2,$y2);
my $level = ceil (log($r_hi+.1) * (1/log(sqrt(5))));
if ($level < 1) { $level = 1; }
return (0, 3**$level - 1);
}
1;
__END__
=for stopwords eg Ryde
=head1 NAME
Math::PlanePath::QuintetSide -- one side of the quintet tiling
=head1 SYNOPSIS
use Math::PlanePath::QuintetSide;
my $path = Math::PlanePath::QuintetSide->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
This path is ...
...
|
26----27
|
24----25
|
23----22
|
20----21
|
18----19
|
17----16
|
15----14
|
13----12 6
|
11----10 5
|
8---- 9 4
|
6---- 7 3
|
5---- 4 2
|
2---- 3 1
|
0---- 1 <- Y=0
^
X=0 1 2 3
It slowly spirals around counter clockwise, with a lot of wiggling in
between. The N=3^level point is at
N = 3^level
angle = level * atan(1/2)
= level * 26.56 degrees
radius = sqrt(5) ^ level
A full revolution for example takes roughly level=14 which is about
N=4,780,000.
Both ends of such levels are in fact sub-spirals, like an "S" shape.
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::QuintetSide-Enew ()>
Create and return a new path object.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
Fractional C<$n> gives a point on the straight line between surrounding
integer N.
=back
=head1 SEE ALSO
L,
L
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/ParabolicRows.pm 0000644 0001750 0001750 00000007206 12250720133 021416 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A056520 1,2,6,15 (n+2)*(2*n^2-n+3)/6 starting n=0
#
package Math::PlanePath::ParabolicRows;
use 5.004;
use strict;
#use List::Util 'min', 'max';
*min = \&Math::PlanePath::_min;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant n_frac_discontinuity => .5;
# first N in row, counting from N=1 at X=0,Y=0
# [ 0,1,2,3 ],
# [ 1,2,6,15 ]
# N = (1/3 y^3 + 1/2 y^2 + 1/6 y + 1)
# = (2 y^3 + 3 y^2 + y + 1) / 6
# = ((2*y + 3)*y + 1)*y/6 + 1 + $x;
sub n_to_xy {
my ($self, $n) = @_;
### ParabolicRows n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n)) { return ($n,$n); }
my $int = int($n);
$n -= $int;
if (2*$n >= 1) { # if frac>=0.5
$int += 1;
$n -= 1;
}
### $int
### $n
my $yhi = int(sqrt($int)) + 2;
my $y = 0;
for (;;) {
my $ymid = int(($yhi+$y)/2);
### at: "y=$y ymid=$ymid yhi=$yhi"
if ($ymid == $y) {
### assert: $y+1 == $yhi
### found, row starting: ((2*$y + 3)*$y + 1)*$y/6 + 1
### $y
### x: $n + ($int - ((2*$y + 3)*$y + 1)*$y/6)
return ($n + ($int - ((2*$y + 3)*$y + 1)*$y/6 - 1),
$y);
}
### compare: ((2*$ymid + 3)*$ymid + 1)*$ymid/6 + 1
if ($int >= ((2*$ymid + 3)*$ymid + 1)*$ymid/6 + 1) {
$y = $ymid;
} else {
$yhi = $ymid;
}
}
# my $y = 0;
# for (;;) {
# my $max = ($y+1)**2;
# if ($int <= $max) {
# return ($n+$int-1,$y);
# }
# $y++;
# $int -= $max;
# }
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### ParabolicRows xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($y < 0) {
return undef;
}
my $ysquared = ($y+1)*($y+1);
if ($x >= $ysquared) {
return undef;
}
return ((2*$y + 3)*$y + 1)*$y/6 + 1 + $x;
}
# exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### ParabolicRows rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
if ($y1 < 0) {
$y1 *= 0;
}
if ($x1 < 0) {
$x1 *= 0;
} elsif ($x1 >= ($y1+1)*($y1+1)) {
$y1 = _sqrt_ceil($x1+1);
### increase y1 to put x1 in range: $y1
}
### assert: defined $self->xy_to_n ($x1, $y1)
### assert: defined $self->xy_to_n (min($x2,($y2+2)*$y2), $y2)
# monotonic increasing in $x and $y directions, so this is exact
return ($self->xy_to_n ($x1, $y1),
$self->xy_to_n (min($x2,($y2+2)*$y2), $y2));
}
sub _sqrt_ceil {
my ($n) = @_;
my $sqrt = sqrt($n);
if ($sqrt*$sqrt < $n) {
$sqrt += 1;
}
return $sqrt;
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/PyramidReplicate.pm 0000644 0001750 0001750 00000016402 12250720133 022103 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=PyramidReplicate --lines --scale=10
# math-image --path=PyramidReplicate --all --output=numbers_dash --size=80x50
package Math::PlanePath::PyramidReplicate;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow';
# uncomment this to run the ### lines
#use Devel::Comments;
use constant n_start => 0;
# 4 3 2
# 5 0 1
# 6 7 8
#
my @digit_to_x = (0,1,0,-1, -2,-3,-2,-1, 0,-1, 0, 1, 2,1,2,3);
my @digit_to_y = (0,0,1, 0, 1, 1, 0, 1, -1,-1,-2,-1, 1,1,0,1);
sub n_to_xy {
my ($self, $n) = @_;
### PyramidReplicate n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
{
my $int = int($n);
### $int
### $n
if ($n != $int) {
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $frac = $n - $int; # inherit possible BigFloat
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int; # BigFloat int() gives BigInt, use that
}
my $x = my $y = ($n * 0); # inherit bignum 0
my $len = ($x + 1); # inherit bignum 1
my $bx = 1;
my $by = 1;
while ($n) {
my $digit = $n % 16;
$n = int($n/16);
### at: "$x,$y"
### $digit
$x += $digit_to_x[$digit] * $bx;
$y += $digit_to_y[$digit] * $by;
$bx *= 6;
$by *= 4;
}
### final: "$x,$y"
return ($x,$y);
}
# mod digit
# 5 3 4 4 3 2 (x mod 3) + 3*(y mod 3)
# 2 0 1 5 0 1
# 8 6 7 6 7 8
#
my @mod_to_digit = (0,1,5, 3,2,4, 7,8,6);
sub xy_to_n {
my ($self, $x, $y) = @_;
### PyramidReplicate xy_to_n(): "$x, $y"
return undef;
$x = round_nearest ($x);
$y = round_nearest ($y);
my ($len,$level_limit);
{
my $xa = abs($x);
my $ya = abs($y);
($len,$level_limit) = round_down_pow (2*($xa > $ya ? $xa : $ya) || 1, 3);
### $level_limit
### $len
}
$level_limit += 2;
if (is_infinite($level_limit)) {
return $level_limit;
}
my $n = ($x * 0 * $y); # inherit bignum 0
my $power = ($n + 1); # inherit bignum 1
while ($x || $y) {
if ($level_limit-- < 0) {
### oops, level limit reached ...
return undef;
}
my $m = ($x % 3) + 3*($y % 3);
my $digit = $mod_to_digit[$m];
### at: "$x,$y m=$m digit=$digit"
$x -= $digit_to_x[$digit];
$y -= $digit_to_y[$digit];
### subtract: "$digit_to_x[$digit],$digit_to_y[$digit] to $x,$y"
### assert: $x % 3 == 0
### assert: $y % 3 == 0
$x /= 3;
$y /= 3;
$n += $digit * $power;
$power *= 9;
}
return $n;
}
# level N Xmax
# 1 9^1-1 1
# 2 9^2-1 1+3
# 3 9^3-1 1+3+9
# X <= 3^0+3^1+...+3^(level-1)
# X <= 1 + 3^0+3^1+...+3^(level-1)
# X <= (3^level - 1)/2
# 2*X+1 <= 3^level
# level >= log3(2*X+1)
#
# X < 1 + 3^0+3^1+...+3^(level-1)
# X < 1 + (3^level - 1)/2
# (3^level - 1)/2 > X-1
# 3^level - 1 > 2*X-2
# 3^level > 2*X-1
#
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### PyramidReplicate rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $max = abs(round_nearest($x1));
foreach ($y1, $x2, $y2) {
my $m = abs(round_nearest($_));
if ($m > $max) { $max = $m }
}
my ($len,$level) = round_down_pow (2*($max||1)-1, 3);
return (0, 9*$len*$len - 1); # 9^level-1
}
1;
__END__
=for stopwords eg Ryde Math-PlanePath aabbccdd
=head1 NAME
Math::PlanePath::PyramidReplicate -- replicating squares
=head1 SYNOPSIS
use Math::PlanePath::PyramidReplicate;
my $path = Math::PlanePath::PyramidReplicate->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
This is a self-similar replicating pyramid shape made from 4 points each,
4
3
2
1
<- Y=0
-1
-2
-3
-4
^
-4 -3 -2 -1 X=0 1 2 3 4
The base shape is the initial N=0 to N=8 section,
+---+
| 2 |
+---+---+---+
| 3 | 0 | 1 |
+---+---+---+
It then repeats inverted to make a similar shape but upside-down,
+---+---+---+---+---+---+---+
| 5 4 7 | 2 |13 12 15 |
+---+ +---+ +---+ +---+
| 6 | 3 0 1 |14 |
+---+---+---+---+---+
| 9 8 11 |
+---+ +---+
|10 |
+---+
=head2 Level Ranges
A given replication extends to ...
Nlevel = 4^level - 1
- ... <= X <= ...
- ... <= Y <= ...
=head2 Complex Base
This pattern corresponds to expressing a complex integer X+i*Y in base b=...
X+Yi = a[n]*b^n + ... + a[2]*b^2 + a[1]*b + a[0]
using complex digits a[i] encoded in N in integer base 4 ...
a[i] digit N digit
---------- -------
0 0
1 1
i 2
-1 3
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::PyramidReplicate-Enew ()>
Create and return a new path object.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
=back
=head1 SEE ALSO
L,
L,
L,
L,
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/wythoff-lines.pl 0000644 0001750 0001750 00000002543 12161000057 021440 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::WythoffLines;
{
foreach my $shift (-3 .. 17) {
my $path = Math::PlanePath::WythoffLines->new (shift => $shift);
my $x_minimum = $path->x_minimum;
my $y_minimum = $path->y_minimum;
my $m = Math::PlanePath::WythoffLines::_calc_minimum($shift);
printf "%2d %4d %4d %4d\n", $shift, $m, $x_minimum, $y_minimum;
}
exit 0;
}
{
use lib 'xt';
require MyOEIS;
my @values;
for (my $shift = 8; $shift < 28; $shift += 2) {
push @values, Math::PlanePath::WythoffLines::_calc_minimum($shift);
}
print join(',',@values),"\n";
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
}
Math-PlanePath-113/devel/lib/Math/PlanePath/NxNvar.pm 0000644 0001750 0001750 00000006004 12250720133 020056 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::NxNvar;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
sub n_to_xy {
my ($self, $n) = @_;
### NxN n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# d = [ 0, 1, 2, 3, 4 ]
# n = [ 0, 1, 3, 6, 10 ]
# N = (d+1)*d/2
# d = (-1 + sqrt(8*$n+1))/2
my $d = int((sqrt(8*$n+1) - 1) / 2);
$n -= $d*($d+1)/2;
### $d
### $n
my $x = $d-$n; # downwards
my $y = $n; # upwards
my $diff = $x-$y;
### diagonals xy: "$x, $y diff=$diff"
if ($diff < 0) {
return (2*$x + (($diff+1) % 2),
2*$x + int((-$diff + ($diff%2))/2));
} elsif ($diff < 3) {
return (2*$y + $diff,
2*$y);
} else {
return (2*$y + int(($diff+1)/2) + (($diff+1) % 2),
2*$y + ($diff % 2));
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### NxN xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
return undef;
if ($x <= $y) {
my $h = int($x/2);
($x,$y) = ($h,
$h + ($x%2) + 2*($y - 2*$h - ($x%2)));
} else {
my $h = int($y/2);
($x,$y) = (1 + $h + ($y%2) + 2*($x-1 - 2*$h - ($y%2)),
$h);
}
return (($x+$y)**2 + $x+3*$y)/2;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### NxN rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
return (0, $x2 * $y2);
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffDifference-oeis.t 0000644 0001750 0001750 00000006545 12113223613 023040 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
MyTestHelpers::nowarnings();
use MyOEIS;
use Math::PlanePath::WythoffDifference;
sub BIGINT {
require Math::NumSeq::PlanePathN;
return Math::NumSeq::PlanePathN::_bigint();
}
#------------------------------------------------------------------------------
# A191361 -- Wythoff difference array X-Y, diagonal containing n
MyOEIS::compare_values
(anum => 'A191361',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffDifference->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $x-$y;
}
return \@got;
});
#------------------------------------------------------------------------------
# A080164 -- Wythoff difference array by anti-diagonals
MyOEIS::compare_values
(anum => 'A080164',
func => sub {
my ($count) = @_;
require Math::PlanePath::Diagonals;
my $path = Math::PlanePath::WythoffDifference->new;
my $diag = Math::PlanePath::Diagonals->new (direction => 'up');
my @got;
for (my $d = $diag->n_start; @got < $count; $d++) {
my ($x,$y) = $diag->n_to_xy($d); # by anti-diagonals
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A000201 -- Wythoff difference Y axis
# lower Wythoff sequence, spectrum of phi
MyOEIS::compare_values
(anum => 'A000201',
max_count => 200,
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffDifference->new;
my @got;
for (my $y = BIGINT()->new(0); @got < $count; $y++) {
push @got, $path->xy_to_n (0, $y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A001519 -- Wythoff difference X axis, a(n) = 3*a(n-1) - a(n-2)
# A122367
MyOEIS::compare_values
(anum => 'A122367',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffDifference->new;
my @got;
for (my $x = BIGINT()->new(0); @got < $count; $x++) {
push @got, $path->xy_to_n ($x, 0);
}
return \@got;
});
MyOEIS::compare_values
(anum => 'A001519',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffDifference->new;
my @got = (1); # extra initial 1
for (my $x = BIGINT()->new(0); @got < $count; $x++) {
push @got, $path->xy_to_n ($x, 0);
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/devel/lib/Math/PlanePath/BalancedArray.pm 0000644 0001750 0001750 00000006411 12251673620 021345 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::BalancedArray;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::NumSeq::BalancedBinary;
# uncomment this to run the ### lines
#use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant xy_is_visited => 1;
sub new {
my $self = shift->SUPER::new (@_);
$self->{'seq'} = Math::NumSeq::BalancedBinary->new;
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### BalancedArray n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my $value = $self->{'seq'}->ith($n)||0;
### value: sprintf '%#b', $value
my $x = 0;
while (($value % 4) == 2) {
$x++;
$value -= 2;
$value /= 4;
}
return ($x,
$value ? $self->{'seq'}->value_to_i($value) : 0);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### BalancedArray xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
my $zero = $x * 0 * $y;
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
my $value = $self->{'seq'}->ith($y) || 0;
### value at y: $value
my $pow = (4+$zero)**$x;
$value *= $pow;
$value += 2*($pow-1)/3;
### mul: sprintf '%#b', $pow
### add: sprintf '%#b', 2*($pow-1)/3
### value: sprintf '%#b', $value
### $value
### value: ref $value && $value->as_bin
return $self->{'seq'}->value_to_i($value);
}
# exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### BalancedArray rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
# bottom left into first quadrant
if ($x1 < 0) { $x1 *= 0; }
if ($y1 < 0) { $y1 *= 0; }
return (0,
4**($x2+$y2));
return ($self->xy_to_n($x1,$y1), # bottom left
$self->xy_to_n($x2,$y2)); # top right
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/WythoffTriangle-oeis.t 0000644 0001750 0001750 00000003750 12112751302 022546 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'max';
use Test;
plan tests => 46;
use lib 't','xt';
use MyTestHelpers;
MyTestHelpers::nowarnings();
use MyOEIS;
use Math::PlanePath::WythoffTriangle;
#------------------------------------------------------------------------------
# A166310 Wythoff Triangle, N by rows
MyOEIS::compare_values
(anum => 'A166310',
func => sub {
my ($count) = @_;
require Math::PlanePath::PyramidRows;
my $path = Math::PlanePath::WythoffTriangle->new;
my $rows = Math::PlanePath::PyramidRows->new (step=>1);
my @got;
for (my $r = $rows->n_start; @got < $count; $r++) {
my ($x,$y) = $rows->n_to_xy($r); # by rows
$y += 1;
push @got, $path->xy_to_n($x,$y);
}
return \@got;
});
#------------------------------------------------------------------------------
# A165359 column 1 of left justified Wythoff, gives triangle Y
MyOEIS::compare_values
(anum => 'A165359',
func => sub {
my ($count) = @_;
my $path = Math::PlanePath::WythoffTriangle->new;
my @got;
for (my $n = $path->n_start; @got < $count; $n++) {
my ($x,$y) = $path->n_to_xy($n);
push @got, $y;
}
return \@got;
});
#------------------------------------------------------------------------------
exit 0;
Math-PlanePath-113/devel/lib/Math/PlanePath/PowerRows.pm 0000644 0001750 0001750 00000007561 12250720133 020622 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::PowerRows;
use 5.004;
use strict;
#use List::Util 'min', 'max';
*min = \&Math::PlanePath::_min;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow';
use constant class_y_negative => 0;
use constant n_frac_discontinuity => .5;
use constant parameter_info_array =>
[ Math::PlanePath::Base::Digits::parameter_info_radix2(),
{ name => 'align',
type => 'enum',
share_key => 'align_rl',
display => 'Align',
default => 'right',
choices => ['right', 'left'],
choices_display => ['Right', 'Left'],
},
];
sub x_minimum {
my ($self) = @_;
return ($self->{'align'} eq 'right' ? 0 : undef);
}
sub x_maximum {
my ($self) = @_;
return ($self->{'align'} eq 'left' ? 0 : undef);
}
#------------------------------------------------------------------------------
sub new {
my $self = shift->SUPER::new(@_);
$self->{'align'} ||= 'right';
$self->{'radix'} ||= 2;
return $self;
}
# Nrow = 1/2 + (r + r + r^2 + ... + r^(depth-1))
# = 1/2 + (r^depth - 1) / (r-1)
# (N-1/2)*(r-1) = r^depth - 1
# r^depth = (N-1/2)*(r-1) + 1
# = (2N-1)*(r-1)/2 + 1
# 2Nrow = 1 + 2*(r^depth - 1) / (r-1);
# = 1 + 2*(pow - 1) / (r-1);
#
sub n_to_xy {
my ($self, $n) = @_;
### PowerRows n_to_xy(): $n
$n *= 2;
if ($n < 1) { return; }
if (is_infinite($n)) { return ($n,$n); }
my $radix = $self->{'radix'};
my ($pow, $y) = round_down_pow (($n-1)*($radix-1)/2 + 1,
$radix);
if ($self->{'align'} eq 'left') {
$n -= 2*$pow;
} else {
$n -= 2;
}
return ($n/2 - ($pow-1)/($radix-1), $y);
}
# uncomment this to run the ### lines
# use Smart::Comments;
sub xy_to_n {
my ($self, $x, $y) = @_;
### PowerRows xy_to_n(): "$x, $y"
$y = round_nearest ($y);
if ($y < 0) {
### all Y negative ...
return undef;
}
my $radix = $self->{'radix'};
my $zero = $x * 0 * $y;
$y = ($radix + $zero) ** $y;
### Y power: $y
$x = round_nearest ($x);
if ($self->{'align'} eq 'left') {
if ($x > 0 || $x <= -$y) {
### X outside 0 to -R^Y ...
return undef;
}
$x += $y;
$x -= 1;
} else {
if ($x < 0 || $x >= $y) {
### X outside 0 to R^Y ...
return undef;
}
}
# Nrow = 1 + (r^depth - 1) / (r-1)
return $x + ($y-1)/($radix-1) + 1;
}
# Nrow = 1 + (r^Y - 1) / (r-1)
# Nlast = Nrow(Y+1)-1
# = 1 + (r^(Y+1) - 1) / (r-1) - 1
# = (r^(Y+1) - 1) / (r-1)
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### PowerRows rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($y2 < 0
|| ($self->{'align'} eq 'right' ? $x2 < 0 : $x1 > 0)) {
### all outside ...
return (1, 0);
}
my $radix = $self->{'radix'};
my $zero = $x1 * 0 * $x2 * $y1 * $y2;
return (1,
(($radix + $zero) ** ($y2+1) - 1) / ($radix-1))
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/PeanoHalf.pm 0000644 0001750 0001750 00000023676 12250720133 020515 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=PeanoHalf,arms=2 --all --output=numbers_dash
# http://www.nahee.com/spanky/www/fractint/lsys/variations.html
# http://www.nahee.com/spanky/www/fractint/lsys/moore.gif
# William McWorter mcworter@midohio.net
package Math::PlanePath::PeanoHalf;
use 5.004;
use strict;
use List::Util 'min'; # 'max'
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::PeanoCurve;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant parameter_info_array =>
[ { name => 'radix',
share_key => 'radix_3',
display => 'Radix',
type => 'integer',
minimum => 2,
default => 3,
width => 3,
},
{ name => 'arms',
share_key => 'arms_2',
display => 'Arms',
type => 'integer',
minimum => 1,
maximum => 2,
default => 1,
width => 1,
description => 'Arms',
} ];
sub new {
my $self = shift->SUPER::new(@_);
if (! $self->{'radix'} || $self->{'radix'} < 2) {
$self->{'radix'} = 3;
}
$self->{'arms'} = max(1, min(2, $self->{'arms'} || 1));
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### PeanoHalf n_to_xy(): $n
if ($n < 0) { return; }
my $arms = $self->{'arms'};
my $x_reverse;
if ($arms > 1) {
my $int = int($n);
my $x_reverse = _divrem_mutate($int,2);
$int = -$int;
} else {
$x_reverse = 0;
}
my $radix = $self->{'radix'};
my ($len, $level) = round_down_pow (2*$n*$radix, $radix);
### $len
### peano at: $n + ($len*$len-1)/2
my ($x,$y) = $self->Math::PlanePath::PeanoCurve::n_to_xy($n + ($len*$len-1)/2);
my $half = ($len-1)/2;
my $y_reverse;
if ($radix % 2) {
$x_reverse ^= ($level & 1);
$y_reverse = $x_reverse ^ 1;
} else {
$y_reverse = $x_reverse;
}
if ($x_reverse) {
$x = $half - $x;
} else {
$x -= $half;
}
if ($y_reverse) {
$y = $half - $y;
} else {
$y -= $half;
}
return ($x, $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### PeanoHalf xy_to_n(): "$x, $y"
return undef;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### PeanoHalf rect_to_n_range(): "$x1,$y1, $x2,$y2"
$x1 = round_nearest ($x1);
$x2 = round_nearest ($x2);
$y1 = round_nearest ($y1);
$y2 = round_nearest ($y2);
my $radix = $self->{'radix'};
my $zero = ($x1 * 0 * $y1 * $x2 * $y2); # inherit bignum
my ($len, $level) = round_down_pow ($zero + max(abs($x1),abs($y1),
abs($x2),abs($y2))*2-1,
$radix);
### $len
### $level
$len *= $radix;
return (0,
($len*$len - 1) * $self->{'arms'} / 2);
}
1;
__END__
=for stopwords eg Ryde ie PeanoHalf Math-PlanePath Moore
=head1 NAME
Math::PlanePath::PeanoHalf -- 9-segment self-similar spiral
=head1 SYNOPSIS
use Math::PlanePath::PeanoHalf;
my $path = Math::PlanePath::PeanoHalf->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
This is an integer version of a 9-segment self-similar curve by ...
=cut
# math-image --path=PeanoHalf --expression='i<=44?i:0' --output=numbers_dash
=pod
7-- 6-- 5-- 4-- 3-- 2 1
| |
8-- 9--10 0-- 1 <- Y=0
|
13--12--11 -1
|
14--15--16 29--30--31--32--33--34 -2
| | |
19--18--17 28--27--26 37--36--35 ...--44 -3
| | | |
20--21--22--23--24--25 38--39--40--41--42--43 -4
^
-4 -3 -2 -1 X=0 1 2 3 4 5 6 7
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
******************************************************
*************************** *********
*************************** *********
*************************** *********
*************************** ****** *********
*************************** *** ** *********
*************************** *** *********
*************************** ******************
*************************** ******************
*************************** ******************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
=head2 Arms
The optional C 2> parameter can give a second copy of the spiral
rotated 180 degrees. With two arms all points of the plane are covered.
93--91 81--79--77--75 57--55 45--43--41--39 122-124 ..
| | | | | | | | | | |
95 89 83 69--71--73 59 53 47 33--35--37 120 126 132
| | | | | | | | | | |
97 87--85 67--65--63--61 51--49 31--29--27 118 128-130
| | |
99-101-103 22--20 10-- 8-- 6-- 4 13--15 25 116-114-112
| | | | | | | | |
109-107-105 24 18 12 1 0-- 2 11 17 23 106-108-110
| | | | | | | | |
111-113-115 26 16--14 3-- 5-- 7-- 9 19--21 104-102-100
| | |
129-127 117 28--30--32 50--52 62--64--66--68 86--88 98
| | | | | | | | | | |
131 125 119 38--36--34 48 54 60 74--72--70 84 90 96
| | | | | | | | | | |
.. 123-121 40--42--44--46 56--58 76--78--80--82 92--94
The first arm is the even numbers N=0,2,4,etc and the second arm is the odd
numbers N=1,3,5,etc.
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::PeanoHalf-Enew ()>
Create and return a new path object.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
=back
=head1 FORMULAS
=head2 X,Y to N
The correspondence to Wunderlich's 3x3 serpentine curve can be used to turn
X,Y coordinates in base 3 into an N. Reckoning the innermost 3x3 as level=1
then the smallest abs(X) or abs(Y) in a level is
Xlevelmin = (3^level + 1) / 2
eg. level=2 Xlevelmin=5
which can be reversed as
level = log3floor( max(abs(X),abs(Y)) * 2 - 1 )
eg. X=7 level=log3floor(2*7-1)=2
An offset can be applied to put X,Y in the range 0 to 3^level-1,
offset = (3^level-1)/2
eg. level=2 offset=4
Then a table can give the N base-9 digit corresponding to X,Y digits
Y=2 4 3 2 N digit
Y=1 -1 0 1
Y=0 -2 -3 -4
X=0 X=1 X=2
A current rotation maintains the "S" part directions and is updated by a
table
Y=2 0 +3 0 rotation when descending
Y=1 +1 +2 +1 into sub-part
Y=0 0 +3 0
X=0 X=1 X=2
The negative digits of N represent backing up a little in some higher part.
If N goes negative at any state then X,Y was off the main curve and instead
on the second arm. If the second arm is not of interest the calculation can
stop at that stage.
It no doubt would also work to take take X,Y as balanced ternary digits
1,0,-1, but it's not clear that would be any faster or easier to calculate.
=head1 SEE ALSO
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/NxN.pm 0000644 0001750 0001750 00000006011 12250720133 017343 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::NxN;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
sub n_to_xy {
my ($self, $n) = @_;
### NxN n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
# d = [ 0, 1, 2, 3, 4 ]
# n = [ 0, 1, 3, 6, 10 ]
# N = (d+1)*d/2
# d = (-1 + sqrt(8*$n+1))/2
my $d = int((sqrt(8*$n+1) - 1) / 2);
$n -= $d*($d+1)/2;
### $d
### $n
my $x = $d-$n; # downwards
my $y = $n; # upwards
my $diff = $x-$y;
### diagonals xy: "$x, $y diff=$diff"
if ($diff <= 0) {
### non-pos diff, use x ...
return (2*$x + ($diff % 2),
2*$x + int((1-$diff)/2));
} else {
### pos diff, use y ...
return (2*($y+1) - 1 + int($diff/2),
2*$y + (($diff+1) % 2));
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### NxN xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
if ($x <= $y) {
my $h = int($x/2);
($x,$y) = ($h,
$h + ($x%2) + 2*($y - 2*$h - ($x%2)));
} else {
my $h = int($y/2);
($x,$y) = (1 + $h + ($y%2) + 2*($x-1 - 2*$h - ($y%2)),
$h);
}
return (($x+$y)**2 + $x+3*$y)/2;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### NxN rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
if ($x2 < 0 || $y2 < 0) {
### all outside first quadrant ...
return (1, 0);
}
if ($x1 < 0) { $x1 *= 0; }
if ($y1 < 0) { $y1 *= 0; }
return (0, $x2 * $y2);
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/PlanePath/ZeckendorfTerms.pm 0000644 0001750 0001750 00000007514 12251673620 021767 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# A134561 triangle T(n,k) = k-th number whose Zeckendorf has exactly n terms
# 4180 5777 6387 6620 6709 6743 6756 6761 6763 6764 8361
# 1596 2206 2439 2528 2562 2575 2580 2582 2583 3193 3426
# 609 842 931 965 978 983 985 986 1219 1308 1342
# 232 321 355 368 373 375 376 465 499 512 517
# 88 122 135 140 142 143 177 190 195 197 198
# 33 46 51 53 54 67 72 74 75 80 82
# 12 17 19 20 25 27 28 30 31 32 38
# 4 6 7 9 10 11 14 15 16 18 22
# 1 2 3 5 8 13 21 34 55 89 144
# Y=1 Fibonacci
# Y=2 A095096
# X=1 first with Y many bits is Zeck 101010101
# A027941 Fib(2n+1)-1
# X=2 second with Y many bits is Zeck 1001010101 high 1, low 10101
# A005592 F(2n+1)+F(2n-1)-1
# X=3 third with Y many bits is Zeck 1010010101
# A005592 F(2n+1)+F(2n-1)-1
# X=4 fourth with Y many bits is Zeck 1010100101
package Math::PlanePath::ZeckendorfTerms;
use 5.004;
use strict;
use List::Util 'max';
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
# uncomment this to run the ### lines
# use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant y_minimum => 1;
use constant x_minimum => 1;
use Math::NumSeq::FibbinaryBitCount;
my $fbc = Math::NumSeq::FibbinaryBitCount->new;
my $next_n = 1;
my @n_to_x;
my @n_to_y;
my @yx_to_n;
sub _extend {
my ($self) = @_;
my $n = $next_n++;
my $y = $fbc->ith($n);
my $row = ($yx_to_n[$y] ||= []);
my $x = scalar(@$row) || 1;
$row->[$x] = $n;
$n_to_x[$n] = $x;
$n_to_y[$n] = $y;
}
sub n_to_xy {
my ($self, $n) = @_;
### ZeckendorfTerms n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n) || $n == 0) { return ($n,$n); }
{
# fractions on straight line ?
my $int = int($n);
if ($n != $int) {
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my $y = $fbc->ith($n);
while ($next_n <= $n) {
_extend($self);
}
### $self
return ($n_to_x[$n], $n_to_y[$n]);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### ZeckendorfTerms xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 1 || $y < 1) { return undef; }
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
for (;;) {
if (defined (my $n = $yx_to_n[$y][$x])) {
return $n;
}
_extend($self);
}
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### ZeckendorfTerms rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
return (1, 10000);
# $self->xy_to_n($x2,$y2));
}
1;
__END__
=cut
# math-image --path=ZeckendorfTerms --output=numbers --all --size=60x14
=pod
Math-PlanePath-113/devel/lib/Math/PlanePath/PeanoRounded.pm 0000644 0001750 0001750 00000033752 12250720133 021237 0 ustar gg gg # works, worth having separately ?
# alternating diagonals when even radix ?
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=PeanoRounded --all --output=numbers
# math-image --path=PeanoRounded,radix=5 --lines
#
package Math::PlanePath::PeanoRounded;
use 5.004;
use strict;
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant parameter_info_array =>
[ { name => 'radix',
share_key => 'radix_3',
display => 'Radix',
type => 'integer',
minimum => 2,
default => 3,
width => 3,
} ];
sub new {
my $self = shift->SUPER::new(@_);
if (! $self->{'radix'} || $self->{'radix'} < 2) {
$self->{'radix'} = 3;
}
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### PeanoRounded n_to_xy(): $n
if ($n < 0) { # negative
return;
}
if (is_infinite($n)) {
return ($n,$n);
}
{
# ENHANCE-ME: for odd radix the ends join and the direction can be had
# without a full N+1 calculation
my $int = int($n);
### $int
### $n
if ($n != $int) {
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $frac = $n - $int; # inherit possible BigFloat
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int; # BigFloat int() gives BigInt, use that
}
# low to high
my $x = _divrem_mutate($n,2);
my $y = $x;
my $power = ($n * 0) + 2; # inherit BigInt 2
my $radix = $self->{'radix'};
my @digits = digit_split_lowtohigh($n,$radix);
while (@digits) {
### $n
### $power
{
my $digit = shift @digits; # low to high
if ($digit & 1) {
$y = $power-1 - $y; # 99..99 - Y
}
$x += $power * $digit;
}
last unless @digits;
{
my $digit = shift @digits; # low to high
$y += $power * $digit;
$power *= $radix;
if ($digit & 1) {
$x = $power-1 - $x;
}
}
}
return ($x, $y);
# # high to low
# my $radix = $self->{'radix'};
# my $radix_minus_1 = $radix - 1;
# my (@n);
# while ($n) {
# push @n, $n % $radix; $n = int($n/$radix);
# push @n, $n % $radix; $n = int($n/$radix);
# }
# my $x = 0;
# my $y = 0;
# my $xk = 0;
# my $yk = 0;
# while (@n) {
# {
# my $digit = pop @n;
# $xk ^= $digit;
# $y *= $radix;
# $y += ($yk & 1 ? $radix_minus_1-$digit : $digit);
# }
# {
# my $digit = pop @n;
# $yk ^= $digit;
# $x *= $radix;
# $x += ($xk & 1 ? $radix_minus_1-$digit : $digit);
# }
# }
# ### is: "$x,$y"
# return ($x, $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### PeanoRounded xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) {
return undef;
}
if (is_infinite($x)) {
return $x;
}
if (is_infinite($y)) {
return $y;
}
my $xlow = _divrem_mutate ($x, 2);
my $ylow = _divrem_mutate ($y, 2);
my $radix = $self->{'radix'};
my $radix_minus_1 = $radix - 1;
my @x = digit_split_lowtohigh($x,$radix);
my @y = digit_split_lowtohigh($y,$radix);
push @x, (0) x max(0, scalar(@y) - scalar(@x));
push @y, (0) x max(0, scalar(@x) - scalar(@y));
my $xk = 0;
my $yk = 0;
my $n = 0;
while (@x) {
{
my $digit = pop @y || 0;
if ($yk & 1) {
$digit = $radix_minus_1 - $digit;
}
$n = ($n * $radix) + $digit;
$xk ^= $digit;
}
{
my $digit = pop @x || 0;
if ($xk & 1) {
$digit = $radix_minus_1 - $digit;
}
$n = ($n * $radix) + $digit;
$yk ^= $digit;
}
}
if ($yk & 1) {
$ylow = 1-$ylow;
}
if ($xk & 1) {
$xlow = 1-$xlow;
}
$n *= 2;
if ($xlow == 0 && $ylow == 0) {
return $n;
} elsif ($xlow == 1 && $ylow == 1) {
return $n + 1;
}
return undef;
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
### rect_to_n_range(): "$x1,$y1 to $x2,$y2"
if ($x2 < 0 || $y2 < 0) {
return (1, 0);
}
my $radix = $self->{'radix'};
my ($power, $level) = round_down_pow (max($x2,$y2)*$radix/2, $radix);
if (is_infinite($level)) {
return (0, $level);
}
return (0, 2*$power*$power - 1);
# Would need to backtrack if the rectangle misses the 2/4 cells filled ...
# my $n_power = 2 * $power * $power * $radix;
# my $max_x = 0;
# my $max_y = 0;
# my $max_n = 0;
# my $max_xk = 0;
# my $max_yk = 0;
#
# my $min_x = 0;
# my $min_y = 0;
# my $min_n = 0;
# my $min_xk = 0;
# my $min_yk = 0;
#
# # l<=cc2 or h-1c2 or h<=c1
# # so does overlap if
# # l<=c2 and h>c1
# #
# my $radix_minus_1 = $radix - 1;
# my $overlap = sub {
# my ($c,$ck,$digit, $c1,$c2) = @_;
# if ($ck & 1) {
# $digit = $radix_minus_1 - $digit;
# }
# ### overlap consider: "inv".($ck&1)."digit=$digit ".($c+$digit*$power)."<=c<".($c+($digit+1)*$power)." cf $c1 to $c2 incl"
# return ($c + $digit*$power <= $c2
# && $c + ($digit+1)*$power > $c1);
# };
#
# while ($level-- >= 0) {
# ### $power
# ### $n_power
# ### $max_n
# ### $min_n
# {
# my $digit;
# for ($digit = $radix_minus_1; $digit > 0; $digit--) {
# last if &$overlap ($max_y,$max_yk,$digit, $y1,$y2);
# }
# $max_n += $n_power * $digit;
# $max_xk ^= $digit;
# if ($max_yk&1) { $digit = $radix_minus_1 - $digit; }
# $max_y += $power * $digit;
# ### max y digit (complemented): $digit
# ### $max_y
# ### $max_n
# }
# {
# my $digit;
# for ($digit = 0; $digit < $radix_minus_1; $digit++) {
# last if &$overlap ($min_y,$min_yk,$digit, $y1,$y2);
# }
# $min_n += $n_power * $digit;
# $min_xk ^= $digit;
# if ($min_yk&1) { $digit = $radix_minus_1 - $digit; }
# $min_y += $power * $digit;
# ### min y digit (complemented): $digit
# ### $min_y
# ### $min_n
# }
#
# $n_power = int($n_power/$radix);
# {
# my $digit;
# for ($digit = $radix_minus_1; $digit > 0; $digit--) {
# last if &$overlap ($max_x,$max_xk,$digit, $x1,$x2);
# }
# $max_n += $n_power * $digit;
# $max_yk ^= $digit;
# if ($max_xk&1) { $digit = $radix_minus_1 - $digit; }
# $max_x += $power * $digit;
# ### max x digit (complemented): $digit
# ### $max_x
# ### $max_n
# }
# {
# my $digit;
# for ($digit = 0; $digit < $radix_minus_1; $digit++) {
# last if &$overlap ($min_x,$min_xk,$digit, $x1,$x2);
# }
# $min_n += $n_power * $digit;
# $min_yk ^= $digit;
# if ($min_xk&1) { $digit = $radix_minus_1 - $digit; }
# $min_x += $power * $digit;
# ### min x digit (complemented): $digit
# ### $min_x
# ### $min_n
# }
#
# $power = int($power/$radix);
# $n_power = int($n_power/$radix);
# }
#
# ### is: "$min_n at $min_x,$min_y to $max_n at $max_x,$max_y"
# return ($min_n, $max_n);
}
1;
__END__
=for stopwords Guiseppe Peano Peano's eg Sur une courbe qui remplit toute aire Mathematische Annalen Ryde OEIS ZOrderCurve ie PeanoCurve Math-PlanePath versa Online Radix radix HilbertCurve
=head1 NAME
Math::PlanePath::PeanoRounded -- 3x3 self-similar quadrant traversal, with rounded corners
=head1 SYNOPSIS
use Math::PlanePath::PeanoRounded;
my $path = Math::PlanePath::PeanoRounded->new;
my ($x, $y) = $path->n_to_xy (123);
# or another radix digits ...
my $path5 = Math::PlanePath::PeanoRounded->new (radix => 5);
=head1 DESCRIPTION
This is a version of the PeanoCurve with rounded-off corners,
11 | 76-75 72-71 68-67
| / \ / \ / \
10 | 77 74-73 70-69 66
| | |
9 | 78 81-82 61-62 65
| \ / \ / \ /
8 | 79-80 83 60 63-64
| | |
7 | 88-87 84 59 56-55
| / \ / \ / \
6 | ...-89 86-85 58-57 54
| |
5 | 13-14 17-18 21-22 49-50 53
| / \ / \ / \ / \ /
4 | 12 15-16 19-20 23 48 51-52
| | | |
3 | 11 8--7 28-27 24 47 44-43
| \ / \ / \ / \ / \
2 | 10--9 6 29 26-25 46-45 42
| | | |
1 | 1--2 5 30 33-34 37-38 41
| / \ / \ / \ / \ /
Y=0 | 0 3--4 31-32 35-36 39-40
+------------------------------------------------------
X=0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
=head2 Radix
The C parameter can do the calculation in a base other than 3, using
the same kind of direction reversals. For example radix 5 gives 5x5 groups,
=cut
# math-image --path=PeanoRounded,radix=5 --all --output=numbers_dash
=pod
radix => 5
9 | 41-42 45-46 49-...
| / \ / \ /
8 | 40 43-44 47-48
| | radix=5
7 | 39 36-35 32-31
| \ / \ / \
6 | 38-37 34-33 30
| |
5 | 21-22 25-26 29
| / \ / \ /
4 | 20 23-24 27-28
| |
3 | 19 16-15 12-11
| \ / \ / \
2 | 18-17 14-13 10
| |
1 | 1--2 5--6 9
| / \ / \ /
Y=0 | 0 3--4 7--8
|
+---------------------------------
X=0 1 2 3 4 5 6 7 8 9
If the radix is even then the ends of each group don't join up. For example
in radix 4 N=31 isn't next to N=32.
=cut
# math-image --path=PeanoRounded,radix=4 --all --output=numbers_dash
=pod
7 | 30-29 26-25 32
| / \ / \ \
6 | 31 28-27 24 33--...
| |
5 | 17-18 21-22 |
| / \ / \ |
4 | 16 19-20 23
| |
3 | | 14-13 10--9
| | / \ / \
2 | 15 12-11 8
| |
1 | 1--2 5--6 |
| / \ / \ |
Y=0 | 0 3--4 7
+-----------------------------------------
X=0 1 2 4 5 6 7 8 9 10
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::PeanoRounded-Enew ()>
=item C<$path = Math::PlanePath::PeanoRounded-Enew (radix =E $r)>
Create and return a new path object.
The optional C parameter gives the base for digit splitting. The
default is ternary, C 3>.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
Fractional positions give an X,Y position along a straight line between the
integer positions.
=back
=head1 SEE ALSO
L,
L,
L
Guiseppe Peano, "Sur une courbe, qui remplit toute une aire plane",
Mathematische Annalen, volume 36, number 1, 1890, p157-160
=over
DOI 10.1007/BF01199438
http://www.springerlink.com/content/w232301n53960133/
=back
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/lib/Math/PlanePath/ParabolicRuns.pm 0000644 0001750 0001750 00000004752 12250720133 021416 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::PlanePath::ParabolicRuns;
use 5.004;
use strict;
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
*_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'round_down_pow';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant class_x_negative => 0;
use constant class_y_negative => 0;
sub n_to_xy {
my ($self, $n) = @_;
### ParabolicRuns n_to_xy(): $n
if ($n < 1) { return; }
if (is_infinite($n)) { return ($n,$n); }
$n -= 1;
my @x;
for (my $k = 0; ; $k++) {
$x[$k] = 0;
for (my $y = $k; $y >= 0; $y--) {
my $len = $k-$y+1;
if ($n < $len) {
return ($x[$y] + $n, $y);
}
$x[$y] += $len;
$n -= $len;
}
}
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### ParabolicRuns xy_to_n(): "$x, $y"
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x < 0 || $y < 0) { return undef; }
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
my $n = 1;
my @sx;
for (my $k = 0; ; $k++) {
$sx[$k] = 0;
for (my $sy = $k; $sy >= 0; $sy--) {
my $len = $k-$sy+1;
if ($y == $sy) {
if ($x < $len) {
return ($n + $x);
}
$x -= $len;
}
$n += $len;
}
}
}
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### ParabolicRuns rect_to_n_range(): "$x1,$y1 $x2,$y2"
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
($x1,$x2) = ($x2,$x1) if $x1 > $x2;
($y1,$y2) = ($y2,$y1) if $y1 > $y2;
return (1,
2*($x2+1)*($y2+1)**2);
}
1;
__END__
Math-PlanePath-113/devel/lib/Math/square-radical.pl 0000644 0001750 0001750 00000001662 12171603336 017676 0 ustar gg gg # Copyright 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::SquareRadical;
# uncomment this to run the ### lines
use Smart::Comments;
{
my $s = Math::SquareRadical->new(1);
print "$s\n";
}
{
my $s = Math::SquareRadical->new(1,2,3);
### $s
print "$s\n";
}
exit 0;
Math-PlanePath-113/devel/fractions-tree.pl 0000644 0001750 0001750 00000003200 11745170634 016263 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl fractions-tree.pl
#
# Print the FractionsTree paths in tree form.
#
use 5.004;
use strict;
use Math::PlanePath::FractionsTree;
foreach my $tree_type ('Kepler') {
print "$tree_type tree\n";
my $path = Math::PlanePath::FractionsTree->new
(tree_type => $tree_type);
printf "%31s", '';
foreach my $n (1) {
my ($x,$y) = $path->n_to_xy($n);
print "$x/$y";
}
print "\n";
printf "%15s", '';
foreach my $n (2 .. 3) {
my ($x,$y) = $path->n_to_xy($n);
printf "%-32s", "$x/$y";
}
print "\n";
printf "%7s", '';
foreach my $n (4 .. 7) {
my ($x,$y) = $path->n_to_xy($n);
printf "%-16s", "$x/$y";
}
print "\n";
printf "%3s", '';
foreach my $n (8 .. 15) {
my ($x,$y) = $path->n_to_xy($n);
printf "%-8s", "$x/$y";
}
print "\n";
foreach my $n (16 .. 31) {
my ($x,$y) = $path->n_to_xy($n);
printf "%4s", "$x/$y";
}
print "\n";
print "\n";
}
exit 0;
Math-PlanePath-113/devel/numseq.pl 0000644 0001750 0001750 00000042476 12252764443 014671 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::Trig 'pi';
# uncomment this to run the ### lines
#use Smart::Comments;
{
# max Dir4
require Math::BaseCnv;
# print 4-atan2(2,1)/atan2(1,1)/2,"\n";
require Math::NumSeq::PlanePathDelta;
require Math::NumSeq::PlanePathTurn;
my $realpart = 3;
my $radix = $realpart*$realpart + 1;
my $planepath;
$planepath = "RationalsTree,tree_type=Drib";
$planepath = "UlamWarburtonQuarter";
$planepath = "GosperReplicate";
$planepath = "QuintetReplicate";
$planepath = "RationalsTree,tree_type=HCS";
$planepath = "ToothpickReplicate,parts=1";
$planepath = "CfracDigits,radix=2";
$planepath = "DiagonalRationals,direction=up";
$planepath = "OneOfEight,parts=wedge";
$planepath = "QuadricIslands";
$planepath = "WunderlichSerpentine";
$planepath = "SacksSpiral";
$planepath = "ComplexMinus,realpart=3";
$planepath = "UlamWarburton,parts=4";
$planepath = "ToothpickTreeByCells,parts=two_horiz";
$planepath = "LCornerTreeByCells,parts=octant_up+1";
$planepath = "ChanTree,k=5";
$planepath = "ComplexPlus,realpart=2";
$planepath = "CfracDigits,radix=".($radix-1);
$planepath = "GosperIslands";
$planepath = "ImaginaryHalf"; # ,digit_order=XnXY";
$planepath = "SquareReplicate";
$planepath = "GrayCode,radix=$radix,apply_type=Ts";
$planepath = "SquareReplicate";
$planepath = "ToothpickTree,parts=2";
$planepath = "ToothpickUpist";
$planepath = "CornerReplicate";
$radix = 3;
$planepath = "ZOrderCurve,radix=$radix";
$planepath = "LCornerReplicate";
$planepath = "LCornerTree,parts=diagonal-1";
$planepath = "WythoffArray";
$planepath = "PowerArray,radix=$radix";
$planepath = "DigitGroups,radix=$radix";
$planepath = "FactorRationals,sign_encoding=negabinary";
$planepath = "GcdRationals,pairs_order=diagonals_up";
$planepath = "LTiling";
$planepath = "TriangularHypot,points=hex_rotated";
$planepath = "Hypot,points=all";
$planepath = "MultipleRings,step=3";
$planepath = "ArchimedeanChords";
$planepath = "DragonMidpoint";
$planepath = "HexSpiral,wider=1";
$planepath = "AlternatePaper";
$planepath = "VogelFloret";
$planepath = "MultipleRings,step=6,ring_shape=polygon";
$planepath = "PythagoreanTree,coordinates=MC,tree_type=UMT";
$planepath = "HTree";
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
# delta_type => 'dX',
# delta_type => 'Dir4',
#delta_type => 'dRadius',
# delta_type => 'dRSquared',
delta_type => 'dDiffXY',
# delta_type => 'TDir6',
# delta_type => 'dAbsDiff',
);
# my $seq = Math::NumSeq::PlanePathTurn->new (planepath => $planepath,
# turn_type => 'Turn4',
# );
my $dx_seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
delta_type => 'dX');
my $dy_seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
delta_type => 'dY');
my $min = 99;
my $max = -99;
for (1 .. 10000000) {
my ($i, $value) = $seq->next;
# $seq->seek_to_i(2*$i+2);
if ($value > $max) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $prev_dx = $dx_seq->ith($i-1) // 'u';
my $prev_dy = $dy_seq->ith($i-1) // 'u';
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dy && $dx/$dy;
$max = $value;
printf "max i=%d[%s] %.5f px=%s,py=%s dx=%s,dy=%s[%s,%s] %.3f\n",
$i,$ri, $value,
$prev_dx,$prev_dy,
$dx,$dy, $rdx,$rdy, $f;
}
if ($value < $min) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $prev_dx = $dx_seq->ith($i-1) // 'u';
my $prev_dy = $dy_seq->ith($i-1) // 'u';
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dy && $dx/$dy;
$min = $value;
printf " min i=%d[%s] %.5f px=%s,py=%s dx=%s,dy=%s %.3f\n",
$i,$ri, $value,
$prev_dx,$prev_dy,
$dx,$dy, $f;
}
}
exit 0;
}
{
# min/max PlanePathCoord
require Math::BaseCnv;
require Math::NumSeq::PlanePathCoord;
my $realpart = 3;
my $radix = $realpart*$realpart + 1;
my $planepath;
$planepath = "MultipleRings,step=3";
$planepath = "MultipleRings,step=3,ring_shape=polygon";
my $seq = Math::NumSeq::PlanePathCoord->new (planepath => $planepath,
coordinate_type => 'AbsDiff');
my $path = $seq->{'planepath_object'};
my $min = 99;
my $max = -99;
for (1 .. 10000000) {
my ($i, $value) = $seq->next;
# if ($value > $max) {
# my $dx = $dx_seq->ith($i);
# my $dy = $dy_seq->ith($i);
# my $prev_dx = $dx_seq->ith($i-1) // 'u';
# my $prev_dy = $dy_seq->ith($i-1) // 'u';
# my $ri = Math::BaseCnv::cnv($i,10,$radix);
# my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
# my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
# my $f = $dy && $dx/$dy;
# $max = $value;
# printf "max i=%d[%s] %.5f px=%s,py=%s dx=%s,dy=%s[%s,%s] %.3f\n",
# $i,$ri, $value,
# $prev_dx,$prev_dy,
# $dx,$dy, $rdx,$rdy, $f;
# }
if ($value < $min) {
my ($x,$y) = $path->n_to_xy($i);
$min = $value;
my $ri = Math::BaseCnv::cnv($i,10,$radix);
printf " min i=%d[%s] %.5f x=%s,y=%s\n",
$i,$ri, $value, $x,$y;
}
}
exit 0;
}
{
require Math::NumSeq::PlanePathDelta;
for (my $a = 0; $a <= 360; $a += 5) {
print "$a ",Math::NumSeq::PlanePathDelta::_dir360_to_tdir6($a),"\n";
}
exit 0;
}
{
# kronecker cf A215200
require Math::NumSeq::PlanePathCoord;
foreach my $n (1 .. 10) {
foreach my $k (1 .. $n) {
my $x = $n - $k;
my $y = $k;
my $kron = Math::NumSeq::PlanePathCoord::_kronecker_symbol($x,$y);
printf "%3d,", $kron;
}
print "\n";
}
exit 0;
}
{
# axis increasing
my $radix = 4;
my $rsquared = $radix * $radix;
my $re = '.' x $radix;
require Math::NumSeq::PlanePathN;
my $planepath;
$planepath = "AlternatePaperMidpoint,arms=7";
$planepath = "ImaginaryBase,radix=37";
$planepath = "ImaginaryHalf,radix=37";
$planepath = "DekkingCurve";
$planepath = "DekkingCentres";
$planepath = "LCornerReplicate";
$planepath = "LCornerTree,parts=3";
LINE_TYPE: foreach my $line_type ('X_axis',
'Y_axis',
'X_neg',
'Y_neg',
'Diagonal_SE',
'Diagonal_SW',
'Diagonal_NW',
'Diagonal',
) {
my $seq = Math::NumSeq::PlanePathN->new
(
planepath => $planepath,
line_type => $line_type,
);
### $seq
my $i_start = $seq->i_start;
my $prev_value = -1;
my $prev_i = -1;
my $i_limit = 10000;
my $i_end = $i_start + $i_limit;
for my $i ($i_start .. $i_end) {
my $value = $seq->ith($i);
next if ! defined $value;
### $value
if ($value <= $prev_value) {
# print "$line_type_type decrease at i=$i value=$value cf prev=$prev\n";
my $path = $seq->{'planepath_object'};
my ($prev_x,$prev_y) = $path->n_to_xy($prev_value);
my ($x,$y) = $path->n_to_xy($value);
print "$line_type not N=$prev_value $prev_x,$prev_y N=$value $x,$y\n";
next LINE_TYPE;
}
$prev_i = $i;
$prev_value = $value;
}
print "$line_type all increasing (to i=$prev_i)\n";
}
exit 0;
}
{
# PlanePathCoord increasing
require Math::NumSeq::PlanePathCoord;
my $planepath;
$planepath = "SierpinskiTriangle,align=right";
COORDINATE_TYPE: foreach my $coordinate_type ('BitAnd',
'BitOr',
'BitXor',
) {
my $seq = Math::NumSeq::PlanePathCoord->new
(
planepath => $planepath,
coordinate_type => $coordinate_type,
);
### $seq
my $i_start = $seq->i_start;
my $prev_value;
my $prev_i;
my $i_limit = 100000;
my $i_end = $i_start + $i_limit;
for my $i ($i_start .. $i_end) {
my $value = $seq->ith($i);
next if ! defined $value;
### $i
### $value
if (defined $prev_value && $value < $prev_value) {
# print "$coordinate_type_type decrease at i=$i value=$value cf prev=$prev\n";
my $path = $seq->{'planepath_object'};
my ($prev_x,$prev_y) = $path->n_to_xy($prev_value);
my ($x,$y) = $path->n_to_xy($value);
print "$coordinate_type not i=$i value=$value cf prev_value=$prev_value\n";
next COORDINATE_TYPE;
}
$prev_i = $i;
$prev_value = $value;
}
print "$coordinate_type all increasing (to i=$prev_i)\n";
}
exit 0;
}
{
# max turn Left etc
require Math::NumSeq::PlanePathTurn;
require Math::NumSeq::PlanePathDelta;
my $planepath;
$planepath = "TriangularHypot,points=hex";
$planepath = "TriangularHypot,points=hex_centred";
$planepath = "TriangularHypot,points=hex_rotated";
$planepath = "ChanTree,k=4";
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => $planepath,
turn_type => 'LSR');
# $planepath = "FractionsTree";
# my $seq = Math::NumSeq::PlanePathDelta->new (planepath => $planepath,
# delta_type => 'Dir4');
my $max = -99;
my $min = 99;
for (1 .. 1000000) {
my ($i, $value) = $seq->next;
# $value = -$value; next unless $value;
if ($value > $max) {
printf "%d %.5f new max\n", $i, $value;
$max = $value;
}
if ($value < $min) {
printf "%d %.5f new min\n", $i, $value;
$min = $value;
}
}
exit 0;
}
{
require Math::BigInt;
my $x = Math::BigInt->new(8);
my $y = Math::BigInt->new(-2);
$x = (8);
$y = (-2);
my $z = $x ^ $y;
print "$z\n";
printf "%b\n", $z & 0xFFF;
if ((($x<0) ^ ($y<0)) != ($z<0)) {
$z = Math::BigInt->new("$z");
$z = ($z - (1<<63)) + -(1<<63);
}
print "$z\n";
printf "%b\n", $z & 0xFFF;
sub sign_extend {
my ($n) = @_;
return ($n - (1<<63)) + -(1<<63);
}
exit 0;
}
{
require Math::NumSeq::PlanePathCoord;
foreach my $path_type (@{Math::NumSeq::PlanePathCoord->parameter_info_array->[0]->{'choices'}}) {
my $class = "Math::PlanePath::$path_type";
### $class
eval "require $class; 1" or die;
my @pinfos = $class->parameter_info_list;
my $params = parameter_info_list_to_parameters(@pinfos);
PAREF:
foreach my $paref (@$params) {
### $paref
my $path = $class->new(@$paref);
my $seq = Math::NumSeq::PlanePathCoord->new(planepath_object => $path,
coordinate_type => 'RSquared');
foreach (1 .. 10) {
$seq->next;
}
foreach (1 .. 1000) {
my ($i, $value) = $seq->next;
if (! defined $i || $value < $i) {
next PAREF;
}
}
print "$path_type ",join(',',@$paref),"\n";
}
}
exit 0;
sub parameter_info_list_to_parameters {
my @parameters = ([]);
foreach my $info (@_) {
info_extend_parameters($info,\@parameters);
}
return \@parameters;
}
sub info_extend_parameters {
my ($info, $parameters) = @_;
my @new_parameters;
if ($info->{'name'} eq 'planepath') {
my @strings;
foreach my $choice (@{$info->{'choices'}}) {
my $path_class = "Math::PlanePath::$choice";
Module::Load::load($path_class);
my @parameter_info_list = $path_class->parameter_info_list;
if ($path_class->isa('Math::PlanePath::Rows')) {
push @parameter_info_list,{ name => 'width',
type => 'integer',
width => 3,
default => '1',
minimum => 1,
};
}
if ($path_class->isa('Math::PlanePath::Columns')) {
push @parameter_info_list, { name => 'height',
type => 'integer',
width => 3,
default => '1',
minimum => 1,
};
}
my $path_parameters
= parameter_info_list_to_parameters(@parameter_info_list);
### $path_parameters
foreach my $aref (@$path_parameters) {
my $str = $choice;
while (@$aref) {
$str .= "," . shift(@$aref) . '=' . shift(@$aref);
}
push @strings, $str;
}
}
### @strings
foreach my $p (@$parameters) {
foreach my $choice (@strings) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'name'} eq 'arms') {
print " skip parameter $info->{'name'}\n";
return;
}
if ($info->{'choices'}) {
my @new_parameters;
foreach my $p (@$parameters) {
foreach my $choice (@{$info->{'choices'}}) {
next if ($info->{'name'} eq 'rotation_type' && $choice eq 'custom');
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'type'} eq 'boolean') {
my @new_parameters;
foreach my $p (@$parameters) {
foreach my $choice (0, 1) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'type'} eq 'integer'
|| $info->{'name'} eq 'multiples') {
my $max = $info->{'minimum'}+10;
if ($info->{'name'} eq 'straight_spacing') { $max = 2; }
if ($info->{'name'} eq 'diagonal_spacing') { $max = 2; }
if ($info->{'name'} eq 'radix') { $max = 17; }
if ($info->{'name'} eq 'realpart') { $max = 3; }
if ($info->{'name'} eq 'wider') { $max = 3; }
if ($info->{'name'} eq 'modulus') { $max = 32; }
if ($info->{'name'} eq 'polygonal') { $max = 32; }
if ($info->{'name'} eq 'factor_count') { $max = 12; }
if (defined $info->{'maximum'} && $max > $info->{'maximum'}) {
$max = $info->{'maximum'};
}
if ($info->{'name'} eq 'power' && $max > 6) { $max = 6; }
my @new_parameters;
foreach my $choice ($info->{'minimum'} .. $max) {
foreach my $p (@$parameters) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'name'} eq 'fraction') {
### fraction ...
my @new_parameters;
foreach my $p (@$parameters) {
my $radix = p_radix($p) || die;
foreach my $den (995 .. 1021) {
next if $den % $radix == 0;
my $choice = "1/$den";
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
foreach my $num (2 .. 10) {
foreach my $den ($num+1 .. 15) {
next if $den % $radix == 0;
next unless _coprime($num,$den);
my $choice = "$num/$den";
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
}
@$parameters = @new_parameters;
return;
}
print " skip parameter $info->{'name'}\n";
}
}
{
my $pi = pi();
my %seen;
foreach my $x (0 .. 100) {
foreach my $y (0 .. 100) {
my $factor;
$factor = 1;
$factor = sqrt(3);
# next unless ($x&1) == ($y&1);
$factor = sqrt(8);
my $radians = atan2($y*$factor, $x);
my $degrees = $radians / $pi * 180;
my $frac = $degrees - int($degrees);
if ($frac > 0.5) {
$frac -= 1;
}
if ($frac < -0.5) {
$frac += 1;
}
my $int = $degrees - $frac;
next if $seen{$int}++;
if ($frac > -0.001 && $frac < 0.001) {
print "$x,$y $int ($degrees)\n";
}
}
}
exit 0;
}
Math-PlanePath-113/devel/biguv.pl 0000644 0001750 0001750 00000002073 11753117277 014464 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Inline 'C';
use Math::BigInt try => 'GMP';
# uncomment this to run the ### lines
use Smart::Comments;
my $big = - Math::BigInt->new(2) ** 65;
### $big
print "big ",ref $big,"\n";
my $uv = touv($big);
print "touv $uv\n";
my $nv = $big->numify;
print "as_number $nv\n";
exit 0;
__END__
__C__
unsigned touv(unsigned n) {
return n;
}
Math-PlanePath-113/devel/exe-complex-minus.c 0000644 0001750 0001750 00000006402 11701770574 016534 0 ustar gg gg /* Copyright 2012 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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 Math-PlanePath. If not, see .
*/
#include
#include
#include
#include
typedef unsigned long my_unsigned;
typedef long long my_signed;
#define MY_SIGNED_ABS llabs
#define HYPOT_LIMIT 0x7FFFFFFF
char *
to_base (unsigned long long n, int radix)
{
static char str[256];
static char dstr[256];
int pos = sizeof(str)-1;
do {
int digit = n % radix;
n /= radix;
sprintf (dstr, "[%d]", digit);
int dlen = strlen(dstr);
pos -= dlen;
memcpy (str+pos, dstr, dlen);
} while (n);
return str+pos;
}
int
base_len (unsigned long long n, int radix)
{
int len = 0;
while (n) {
n /= radix;
len++;
}
return len;
}
int
main (void)
{
int realpart, level;
for (realpart = 3; realpart < 10; realpart++) {
int norm = realpart*realpart + 1;
int level_limit = 20;
if (realpart == 2) level_limit = 10;
if (realpart == 3) level_limit = 9;
if (realpart == 4) level_limit = 9;
for (level = 0; level < level_limit; level++) {
unsigned long long min_h = ~0ULL;
my_unsigned min_n = 0;
my_signed min_x = 0;
my_signed min_y = 0;
{
my_unsigned lo = pow(norm, level);
my_unsigned hi = lo * norm;
printf ("%2d lo=%lu hi=%lu\n", level, lo, hi);
my_unsigned n;
for (n = lo; n < hi; n++) {
my_signed x = 0;
my_signed y = 0;
my_signed bx = 1;
my_signed by = 0;
my_unsigned digits = n;
while (digits != 0) {
int digit = digits % norm;
digits /= norm;
x += digit * bx;
y += digit * by;
/* (bx,by) = (bx + i*by)*(i-$realpart) */
my_signed new_bx = bx*-realpart - by;
my_signed new_by = bx + by*-realpart;
bx = new_bx;
by = new_by;
}
unsigned long long abs_x = MY_SIGNED_ABS(x);
unsigned long long abs_y = MY_SIGNED_ABS(y);
if (abs_x > HYPOT_LIMIT
|| abs_y > HYPOT_LIMIT) {
continue;
}
unsigned long long h = abs_x*abs_x + abs_y*abs_y;
/* printf ("%2d %lu %Ld,%Ld %LX\n", level, n, x,y, h); */
if (h < min_h) {
min_h = h;
min_n = n;
min_x = abs_x;
min_y = abs_y;
}
}
}
/* printf ("%lX %Ld,%Ld %s\n", min_n, min_x,min_y, */
/* binary(min_h)); */
printf ("%2d", level);
printf (" %s [%d]", to_base(min_h,norm), base_len(min_h,norm));
printf ("\n");
/* printf ("\n"); */
}
}
return 0;
}
Math-PlanePath-113/devel/gcd-rationals-integer.pl 0000644 0001750 0001750 00000003250 11702424166 017520 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::GcdRationals;
my $height = 20;
my $path = Math::PlanePath::GcdRationals->new;
my $n_lo = $path->n_start;
my $n_hi = $height*($height+1)/2 - 1;
my @array;
foreach my $n ($n_lo .. $n_hi) {
my ($x,$y) = $path->n_to_xy ($n);
my $int = int($x/$y);
if ($int >= 10) { $int = 'z' }
$array[$y]->[$x] = $int;
}
my $cell_width = max (map {length}
grep {defined}
map {@$_}
grep {defined}
@array);
foreach my $y (reverse 1 .. $#array) {
foreach my $x (1 .. $#{$array[$y]}) {
my $int = $array[$y]->[$x];
if (! defined $int) { $int = ''; }
printf '%*s', $cell_width, $int;
}
print "\n";
}
print "\n";
foreach my $y (reverse 1 .. 20) {
foreach my $x (1 .. $y) {
my $int = Math::PlanePath::GcdRationals::_gcd($x,$y) - 1;
if ($int >= 10) { $int = 'z' }
print "$int";
}
print "\n";
}
exit 0;
Math-PlanePath-113/devel/cont-frac.pl 0000644 0001750 0001750 00000002574 11535000617 015215 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX 'fmod';
use Math::Libm 'M_PI', 'M_E', 'hypot';
use Math::Trig 'pi';
use POSIX;
# sqrt(pi*e/2) = 1 / (1+ 1/(1 + 2/(1+ 3/(1 + 4/(...)))))
{
use Math::BigFloat;
my $rot;
$rot = M_PI;
$rot = sqrt(17);
# $rot = Math::BigFloat->bpi(1000); # PI to 100 digits
# $rot = Math::BigFloat->bsqrt(5);
# $rot = (Math::BigFloat->bsqrt(5) +1) / 2;
$rot = sqrt(M_PI() * M_E() / 2);
$rot = 0.5772156649015328606065120;
$rot = sqrt(5);
foreach (1..30) {
my $int = int($rot);
my $frac = $rot - $int;
print $int,"\n";
$rot = 1/$frac;
}
# use constant ROTATION => PHI;
# use constant ROTATION =>
exit 0;
}
Math-PlanePath-113/devel/Makefile 0000644 0001750 0001750 00000001423 12234416216 014437 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# CFLAGS = -Wall -O0 -g
CFLAGS = -Wall -O2 -DINLINE=inline -g
LOADLIBES = -lm
Math-PlanePath-113/devel/coprime.pl 0000644 0001750 0001750 00000003344 11606533461 015002 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
{
require Math::PlanePath::CoprimeColumns;
my $n = 0;
foreach my $x (3 .. 1000) {
foreach my $y (1 .. $x-1) {
$n += Math::PlanePath::CoprimeColumns::_coprime($x,$y);
}
my $square = $x*$x;
my $frac = $n / $square;
printf "%d %d %d %.3g\n", $x, $n, $square, $frac;
}
exit 0;
}
{
require Math::PlanePath::CoprimeColumns;
foreach my $x (2 .. 100) {
my $n = 0;
my @list;
foreach my $y (1 .. $x-1) {
if (Math::PlanePath::CoprimeColumns::_coprime($x,$y)) {
$n++;
push @list, $y;
}
}
my $c = Math::PlanePath::CoprimeColumns::_totient_count($x);
if ($c != $n) {
die "x=$x tot $c step $n\n";
}
printf "%d %d %s\n", $x, $n, join(',',@list);
}
exit 0;
}
sub _coprime {
my ($x, $y) = @_;
### _coprime(): "$x,$y"
if ($x < $y) {
($x,$y) = ($y,$x);
}
for (;;) {
if ($y <= 0) {
return 0;
}
if ($y == 1) {
return 1;
}
$x %= $y;
($x,$y) = ($y,$x);
}
}
Math-PlanePath-113/devel/complex-revolving.pl 0000644 0001750 0001750 00000007035 11703471336 017025 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
{
# min/max for level
$|=1;
require Math::PlanePath::ComplexRevolving;
my $path = Math::PlanePath::ComplexRevolving->new;
my $prev_max = 1;
my @min = (1);
for (my $level = 1; $level < 25; $level++) {
my $n_start = 2**($level-1);
my $n_end = 2**$level;
my $min_hypot = 128*$n_end*$n_end;
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
# print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + $y*$y;
if ($h < $min_hypot) {
$min_hypot = $h;
$min_pos = "$x,$y";
}
if ($h > $max_hypot) {
$max_hypot = $h;
$max_pos = "$x,$y";
}
}
# print "$min_hypot,";
$min[$level] = $min_hypot;
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $min[$level-1];
my $factor4_level = max($level-4,0);
my $factor4 = $min_hypot / $min[max($factor4_level)];
# printf " min r^2 %5d", $min_hypot;
printf " 0b%-20b", $min_hypot;
# print " at $min_pos";
# print " factor $factor";
# print " factor[$factor4_level] $factor4";
# print " cf formula ", 2**($level-7), "\n";
print "\n";
}
# {
# my $factor = $max_hypot / $prev_max;
# print " max r^2 $max_hypot 0b".sprintf('%b',$max_hypot)." at $max_pos factor $factor\n";
# }
$prev_max = $max_hypot;
}
exit 0;
}
{
require Math::PlanePath::ComplexRevolving;
require Image::Base::Text;
my $realpart = 2;
my $radix = $realpart*$realpart + 1;
my %seen;
my $isize = 20;
my $image = Image::Base::Text->new (-width => 2*$isize+1,
-height => 2*$isize+1);
foreach my $n (0 .. $radix**6) {
my $x = 0;
my $y = 0;
my $bx = 1;
my $by = 0;
foreach my $digit (digits($n,$radix)) {
if ($digit) {
$x += $digit * $bx;
$y += $digit * $by;
($bx,$by) = (-$by,$bx); # (bx+by*i)*i = bx*i - by, rotate +90
}
# (bx,by) = (bx + i*by)*(i+$realpart)
#
($bx,$by) = ($realpart*$bx - $by, $bx + $realpart*$by);
}
my $dup = ($seen{"$x,$y"}++ ? " dup" : "");
printf "%4d %2d,%2d%s\n", $n, $x,$y, $dup;
if ($x > -$isize && $x < $isize
&& $y > -$isize && $y < $isize) {
$image->xy($x+$isize,$y+$isize,'*');
}
}
$image->xy(0+$isize,0+$isize,'+');
$image->save_fh(\*STDOUT);
exit 0;
sub digits {
my ($n, $radix) = @_;
my @ret;
while ($n) {
push @ret, $n % $radix;
$n = int($n/$radix);
}
return @ret;
}
}
Math-PlanePath-113/devel/exe-complex-plus.c 0000644 0001750 0001750 00000006400 11702125647 016356 0 ustar gg gg /* Copyright 2012 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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 Math-PlanePath. If not, see .
*/
#include
#include
#include
#include
typedef unsigned long my_unsigned;
typedef long long my_signed;
#define MY_SIGNED_ABS llabs
#define HYPOT_LIMIT 0x7FFFFFFF
char *
to_base (unsigned long long n, int radix)
{
static char str[256];
static char dstr[256];
int pos = sizeof(str)-1;
do {
int digit = n % radix;
n /= radix;
sprintf (dstr, "[%d]", digit);
int dlen = strlen(dstr);
pos -= dlen;
memcpy (str+pos, dstr, dlen);
} while (n);
return str+pos;
}
int
base_len (unsigned long long n, int radix)
{
int len = 0;
while (n) {
n /= radix;
len++;
}
return len;
}
int
main (void)
{
int realpart, level;
for (realpart = 3; realpart < 10; realpart++) {
int norm = realpart*realpart + 1;
int level_limit = 20;
if (realpart == 2) level_limit = 10;
if (realpart == 3) level_limit = 9;
if (realpart == 4) level_limit = 9;
for (level = 0; level < level_limit; level++) {
unsigned long long min_h = ~0ULL;
my_unsigned min_n = 0;
my_signed min_x = 0;
my_signed min_y = 0;
{
my_unsigned lo = pow(norm, level);
my_unsigned hi = lo * norm;
printf ("%2d lo=%lu hi=%lu\n", level, lo, hi);
my_unsigned n;
for (n = lo; n < hi; n++) {
my_signed x = 0;
my_signed y = 0;
my_signed bx = 1;
my_signed by = 0;
my_unsigned digits = n;
while (digits != 0) {
int digit = digits % norm;
digits /= norm;
x += digit * bx;
y += digit * by;
/* (bx,by) = (bx + i*by)*(i+$realpart) */
my_signed new_bx = bx*realpart - by;
my_signed new_by = bx + by*realpart;
bx = new_bx;
by = new_by;
}
unsigned long long abs_x = MY_SIGNED_ABS(x);
unsigned long long abs_y = MY_SIGNED_ABS(y);
if (abs_x > HYPOT_LIMIT
|| abs_y > HYPOT_LIMIT) {
continue;
}
unsigned long long h = abs_x*abs_x + abs_y*abs_y;
/* printf ("%2d %lu %Ld,%Ld %LX\n", level, n, x,y, h); */
if (h < min_h) {
min_h = h;
min_n = n;
min_x = abs_x;
min_y = abs_y;
}
}
}
/* printf ("%lX %Ld,%Ld %s\n", min_n, min_x,min_y, */
/* binary(min_h)); */
printf ("%2d", level);
printf (" %s [%d]", to_base(min_h,norm), base_len(min_h,norm));
printf ("\n");
/* printf ("\n"); */
}
}
return 0;
}
Math-PlanePath-113/devel/permutations.pl 0000644 0001750 0001750 00000067476 12234656460 016121 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use Module::Load;
use lib 'xt';
use MyOEIS;
# uncomment this to run the ### lines
# use Smart::Comments;
{
# permutation between two paths
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
@choices = grep {$_ ne 'CellularRule'} @choices;
@choices = grep {$_ ne 'Rows'} @choices;
@choices = grep {$_ ne 'Columns'} @choices;
@choices = grep {$_ ne 'ArchimedeanChords'} @choices;
@choices = grep {$_ ne 'MultipleRings'} @choices;
@choices = grep {$_ ne 'VogelFloret'} @choices;
@choices = grep {$_ ne 'PythagoreanTree'} @choices;
@choices = grep {$_ ne 'PeanoHalf'} @choices;
@choices = grep {$_ !~ /EToothpick|LToothpick|Surround|Peninsula/} @choices;
@choices = grep {$_ ne 'CornerReplicate'} @choices;
@choices = grep {$_ ne 'ZOrderCurve'} @choices;
unshift @choices, 'CornerReplicate', 'ZOrderCurve';
@choices = ('PythagoreanTree');
my $num_choices = scalar(@choices);
print "$num_choices choices\n";
my @path_objects;
my %path_fullnames;
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
Module::Load::load($class);
my $parameters = parameter_info_list_to_parameters
($class->parameter_info_list);
foreach my $p (@$parameters) {
my $path_object = $class->new (@$p);
push @path_objects, $path_object;
$path_fullnames{$path_object} = "$name ".join(',',@$p);
}
}
my $num_path_objects = scalar(@path_objects);
print "total path objects $num_path_objects\n";
my $start_t = time();
my $t = $start_t-8;
my $i = 0;
# until ($path_objects[$i]->isa('Math::PlanePath::DiamondArms')) {
# $i++;
# }
# while ($path_objects[$i]->isa('Math::PlanePath::PyramidSpiral')) {
# $i++;
# }
my $start_permutations = $i * ($num_path_objects-1);
my $num_permutations = $num_path_objects * ($num_path_objects-1);
open DEBUG, '>/tmp/permutations.out' or die;
select DEBUG or die; $| = 1; # autoflush
select STDOUT or die;
for ( ; $i <= $#path_objects; $i++) {
my $from_path = $path_objects[$i];
my $from_fullname = $path_fullnames{$from_path};
my $n_start = $from_path->n_start;
PATH: foreach my $j (0 .. $#path_objects) {
if (time()-$t < 0 || time()-$t > 10) {
my $upto_permutation = $i*$num_path_objects + $j || 1;
my $rem_permutation = $num_permutations
- ($start_permutations + $upto_permutation);
my $done_permutations = ($upto_permutation-$start_permutations);
my $percent = 100 * $done_permutations / $num_permutations || 1;
my $t_each = (time() - $start_t) / $done_permutations;
my $done_per_second = $done_permutations / (time() - $start_t);
my $eta = int($t_each * $rem_permutation);
my $s = $eta % 60; $eta = int($eta/60);
my $m = $eta % 60; $eta = int($eta/60);
my $h = $eta;
my $eta_str = sprintf '%d:%02d:%02d', $h,$m,$s;
print "$upto_permutation / $num_permutations est $eta_str (each $t_each)\n";
$t = time();
}
next if $i == $j;
my $to_path = $path_objects[$j];
next if $to_path->n_start != $n_start;
my $to_fullname = $path_fullnames{$to_path};
my $name = "$from_fullname -> $to_fullname";
print DEBUG "$name\n";
my $str = '';
my @values;
foreach my $n ($n_start+2 .. $n_start+50) {
my ($x,$y) = $from_path->n_to_xy($n)
or next PATH;
my $pn = $to_path->xy_to_n($x,$y) // next PATH;
$str .= "$pn,";
push @values, $pn;
}
print MyOEIS->grep_for_values(name => $name,
array => \@values);
# if (defined (my $diff = constant_diff(@values))) {
# print "$from_fullname -> $to_fullname\n";
# print " constant diff $diff\n";
# next PATH;
# }
# if (my $found = stripped_grep($str)) {
# print "$from_fullname -> $to_fullname\n";
# print " (",substr($str,0,20),"...)\n";
# print $found;
# print "\n";
# }
}
}
exit 0;
}
{
# permutation of transpose
require MyOEIS;
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
@choices = grep {$_ ne 'BinaryTerms'} @choices; # bit slow yet
my %seen;
foreach my $path_name (@choices) {
my $path_class = "Math::PlanePath::$path_name";
Module::Load::load($path_class);
my $parameters = parameter_info_list_to_parameters($path_class->parameter_info_list);
PATH: foreach my $p (@$parameters) {
my $name = "$path_name ".join(',',@$p);
my $path = $path_class->new (@$p);
my @values;
foreach my $n ($path->n_start+1 .. 35) {
my $value = (defined $path->tree_n_to_subheight($n) ? 1 : 0);
# my ($x,$y) = $path->n_to_xy($n) or next PATH;
# # my $value = $path->xy_to_n($y,$x);
# my $value = $path->xy_to_n(-$y,-$x);
next PATH if ! defined $value;
push @values, $value;
}
print MyOEIS->grep_for_values(name => $name,
array => \@values);
}
}
exit 0;
}
{
# boundary length by N
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
@choices = grep {$_ ne 'CellularRule'} @choices;
@choices = grep {$_ ne 'ArchimedeanChords'} @choices;
@choices = grep {$_ ne 'TheodorusSpiral'} @choices;
@choices = grep {$_ ne 'MultipleRings'} @choices;
@choices = grep {$_ ne 'VogelFloret'} @choices;
@choices = grep {$_ ne 'UlamWarburtonAway'} @choices;
@choices = grep {$_ !~ /Hypot|ByCells|SumFractions|WythoffTriangle/} @choices;
@choices = grep {$_ ne 'PythagoreanTree'} @choices;
# @choices = grep {$_ ne 'PeanoHalf'} @choices;
@choices = grep {$_ !~ /EToothpick|LToothpick|Surround|Peninsula/} @choices;
#
# @choices = grep {$_ ne 'CornerReplicate'} @choices;
# @choices = grep {$_ ne 'ZOrderCurve'} @choices;
# unshift @choices, 'CornerReplicate', 'ZOrderCurve';
my $num_choices = scalar(@choices);
print "$num_choices choices\n";
@choices = ((grep {/Corner|Tri/} @choices),
(grep {!/Corner|Tri/} @choices));
my @path_objects;
my %path_fullnames;
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
### $class
Module::Load::load($class);
my $parameters = parameter_info_list_to_parameters
($class->parameter_info_list);
foreach my $p (@$parameters) {
my $path_object = $class->new (@$p);
push @path_objects, $path_object;
$path_fullnames{$path_object} = "$name ".join(',',@$p);
}
}
my $num_path_objects = scalar(@path_objects);
print "total path objects $num_path_objects\n";
my $start_t = time();
my $t = $start_t-8;
my $i = 0;
# until ($path_objects[$i]->isa('Math::PlanePath::DragonCurve')) {
# $i++;
# }
my $start_permutations = $i * ($num_path_objects-1);
my $num_permutations = $num_path_objects * ($num_path_objects-1);
for ( ; $i <= $#path_objects; $i++) {
my $path = $path_objects[$i];
my $fullname = $path_fullnames{$path};
print "$fullname\n";
my $x_minimum = $path->x_minimum;
my $y_minimum = $path->y_minimum;
my $str = '';
my @values;
my $boundary = 0;
foreach my $n ($path->n_start .. 30) {
# $boundary += path_n_to_dboundary($path,$n);
# $boundary += path_n_to_dsticks($path,$n);
# $boundary += path_n_to_dhexboundary($path,$n);
$boundary += path_n_to_dhexsticks($path,$n);
my $value = $boundary;
$str .= "$value,";
push @values, $value;
}
shift @values;
if (defined (my $diff = constant_diff(@values))) {
print "$fullname\n";
print " constant diff $diff\n";
next;
}
print "$str\n";
if (my $found = stripped_grep($str)) {
print "$fullname match\n";
print " (",substr($str,0,60),"...)\n";
print $found;
print "\n";
}
}
exit 0;
}
BEGIN {
my @dir4_to_dx = (1,0,-1,0);
my @dir4_to_dy = (0,1,0,-1);
sub path_n_to_dboundary {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n) or return 0;
my $dboundary = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dboundary -= 2*(defined $an && $an < $n);
}
return $dboundary;
}
sub path_n_to_dsticks {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n) or return 0;
my $dsticks = 4;
foreach my $i (0 .. $#dir4_to_dx) {
my $an = $path->xy_to_n($x+$dir4_to_dx[$i], $y+$dir4_to_dy[$i]);
$dsticks -= (defined $an && $an < $n);
}
return $dsticks;
}
}
BEGIN {
my @dir6_to_dx = (2, 1,-1,-2, -1, 1);
my @dir6_to_dy = (0, 1, 1, 0, -1,-1);
sub path_n_to_dhexboundary {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n) or return 0;
my $dboundary = 6;
foreach my $i (0 .. $#dir6_to_dx) {
my $an = $path->xy_to_n($x+$dir6_to_dx[$i], $y+$dir6_to_dy[$i]);
$dboundary -= 2*(defined $an && $an < $n);
}
return $dboundary;
}
sub path_n_to_dhexsticks {
my ($path, $n) = @_;
my ($x,$y) = $path->n_to_xy($n) or return 0;
my $dboundary = 6;
foreach my $i (0 .. $#dir6_to_dx) {
my $an = $path->xy_to_n($x+$dir6_to_dx[$i], $y+$dir6_to_dy[$i]);
$dboundary -= (defined $an && $an < $n);
}
return $dboundary;
}
}
{
# path classes with or without n_start
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
my (@with, @without);
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
Module::Load::load($class);
my $href = $class->parameter_info_hash;
if ($href->{'n_start'}) {
push @with, $class;
} else {
push @without, $class;
}
}
foreach my $aref (\@without, \@with) {
foreach my $class (@$aref) {
my @pnames = map {$_->{'name'}} $class->parameter_info_list;
my $href = $class->parameter_info_hash;
my $w = ($href->{'n_start'} ? 'with' : 'without');
print " $class [$w] ",join(',',@pnames),"\n";
# print " ",join(', ',keys %$href),"\n";
}
print "\n\n";
}
exit 0;
}
{
require Math::PlanePath::DragonCurve;
my $path = Math::PlanePath::DragonCurve->new;
my @values;
foreach my $n (3 .. 32) {
my ($x,$y) = $path->n_to_xy(2*$n);
# push @values,-$x-1;
my $transitions = transitions($n);
push @values, (($transitions%4)/2);
# push @values, $transitions;
}
my $values = join(',',@values);
print "$values\n";
print MyOEIS->grep_for_values_aref(\@values);
exit 0;
# transitions(2n)/2 = A069010 Number of runs of 1's
sub transitions {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += (($n & 3) == 1 || ($n & 3) == 2);
$n >>= 1;
}
return $count
}
}
{
# X,Y at N=2^k
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
@choices = grep {$_ ne 'CellularRule'} @choices;
# @choices = grep {$_ ne 'Rows'} @choices;
# @choices = grep {$_ ne 'Columns'} @choices;
@choices = grep {$_ ne 'ArchimedeanChords'} @choices;
@choices = grep {$_ ne 'TheodorusSpiral'} @choices;
@choices = grep {$_ ne 'MultipleRings'} @choices;
@choices = grep {$_ ne 'VogelFloret'} @choices;
@choices = grep {$_ ne 'UlamWarburtonAway'} @choices;
@choices = grep {$_ !~ /Hypot|ByCells|SumFractions|WythoffTriangle/} @choices;
# @choices = grep {$_ ne 'PythagoreanTree'} @choices;
# @choices = grep {$_ ne 'PeanoHalf'} @choices;
@choices = grep {$_ !~ /EToothpick|LToothpick|Surround|Peninsula/} @choices;
#
# @choices = grep {$_ ne 'CornerReplicate'} @choices;
# @choices = grep {$_ ne 'ZOrderCurve'} @choices;
# unshift @choices, 'CornerReplicate', 'ZOrderCurve';
my $num_choices = scalar(@choices);
print "$num_choices choices\n";
my @path_objects;
my %path_fullnames;
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
### $class
Module::Load::load($class);
my $parameters = parameter_info_list_to_parameters
($class->parameter_info_list);
foreach my $p (@$parameters) {
my $path_object = $class->new (@$p);
push @path_objects, $path_object;
$path_fullnames{$path_object} = "$name ".join(',',@$p);
}
}
my $num_path_objects = scalar(@path_objects);
print "total path objects $num_path_objects\n";
my $start_t = time();
my $t = $start_t-8;
my $i = 0;
until ($path_objects[$i]->isa('Math::PlanePath::DragonCurve')) {
$i++;
}
my $start_permutations = $i * ($num_path_objects-1);
my $num_permutations = $num_path_objects * ($num_path_objects-1);
for ( ; $i <= $#path_objects; $i++) {
my $path = $path_objects[$i];
my $fullname = $path_fullnames{$path};
print "$fullname\n";
foreach my $coord_idx (0, 1) {
my $fullname = $fullname." ".($coord_idx?'Y':'X');
HALF: foreach my $half (0,1) {
my $fullname = $fullname.($half?'/2':'');
my $str = '';
my @values;
foreach my $k (1 .. 20) {
my @coords = $path->n_to_xy(2**$k);
my $value = $coords[$coord_idx];
if ($half) { $value /= 2; }
$str .= "$value,";
push @values, $value;
}
shift @values;
if (defined (my $diff = constant_diff(@values))) {
print "$fullname\n";
print " constant diff $diff\n";
next;
}
if (my $found = stripped_grep($str)) {
print "$fullname match\n";
print " (",substr($str,0,60),"...)\n";
print $found;
print "\n";
}
}
}
}
exit 0;
}
{
# row increments
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
# @choices = grep {$_ ne 'CellularRule'} @choices;
# @choices = grep {$_ ne 'Rows'} @choices;
# @choices = grep {$_ ne 'Columns'} @choices;
# @choices = grep {$_ ne 'ArchimedeanChords'} @choices;
@choices = grep {$_ ne 'MultipleRings'} @choices;
@choices = grep {$_ ne 'VogelFloret'} @choices;
@choices = grep {$_ !~ /ByCells/} @choices;
# @choices = grep {$_ ne 'PythagoreanTree'} @choices;
# @choices = grep {$_ ne 'PeanoHalf'} @choices;
# @choices = grep {$_ !~ /EToothpick|LToothpick|Surround|Peninsula/} @choices;
#
# @choices = grep {$_ ne 'CornerReplicate'} @choices;
# @choices = grep {$_ ne 'ZOrderCurve'} @choices;
# unshift @choices, 'CornerReplicate', 'ZOrderCurve';
my $num_choices = scalar(@choices);
print "$num_choices choices\n";
my @path_objects;
my %path_fullnames;
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
### $class
Module::Load::load($class);
my $parameters = parameter_info_list_to_parameters
($class->parameter_info_list);
foreach my $p (@$parameters) {
my $path_object = $class->new (@$p);
push @path_objects, $path_object;
$path_fullnames{$path_object} = "$name ".join(',',@$p);
}
}
my $num_path_objects = scalar(@path_objects);
print "total path objects $num_path_objects\n";
my $start_t = time();
my $t = $start_t-8;
my $i = 0;
# until ($path_objects[$i]->isa('Math::PlanePath::DiamondArms')) {
# $i++;
# }
my $start_permutations = $i * ($num_path_objects-1);
my $num_permutations = $num_path_objects * ($num_path_objects-1);
for ( ; $i <= $#path_objects; $i++) {
my $path = $path_objects[$i];
my $fullname = $path_fullnames{$path};
my $n_start = $path->n_start;
$path->tree_n_num_children($n_start) or next;
print "$fullname\n";
# if (time()-$t < 0 || time()-$t > 10) {
# my $upto_permutation = $i*$num_path_objects + $j || 1;
# my $rem_permutation = $num_permutations
# - ($start_permutations + $upto_permutation);
# my $done_permutations = ($upto_permutation-$start_permutations);
# my $percent = 100 * $done_permutations / $num_permutations || 1;
# my $t_each = (time() - $start_t) / $done_permutations;
# my $done_per_second = $done_permutations / (time() - $start_t);
# my $eta = int($t_each * $rem_permutation);
# my $s = $eta % 60; $eta = int($eta/60);
# my $m = $eta % 60; $eta = int($eta/60);
# my $h = $eta;
# print "$upto_permutation / $num_permutations est $h:$m:$s (each $t_each)\n";
# $t = time();
# }
my $str = '';
my @values;
foreach my $depth (1 .. 50) {
# my $value = $path->tree_depth_to_width($depth) // next;
my $value = $path->tree_depth_to_n($depth) % 2;
$str .= "$value,";
push @values, $value;
}
if (defined (my $diff = constant_diff(@values))) {
print "$fullname\n";
print " constant diff $diff\n";
next;
}
if (my $found = stripped_grep($str)) {
print "$fullname match\n";
print " (",substr($str,0,60),"...)\n";
print $found;
print "\n";
}
}
exit 0;
}
{
require Math::NumSeq::PlanePathCoord;
my @choices = @{Math::NumSeq::PlanePathCoord->parameter_info_hash
->{'planepath'}->{'choices'}};
my $num_choices = scalar(@choices);
print "$num_choices choices\n";
my @path_objects;
my %path_fullnames;
foreach my $name (@choices) {
my $class = "Math::PlanePath::$name";
Module::Load::load($class);
my $parameters = parameter_info_list_to_parameters
($class->parameter_info_list);
foreach my $p (@$parameters) {
my $path_object = $class->new (@$p);
push @path_objects, $path_object;
$path_fullnames{$path_object} = "$name ".join(',',@$p);
}
}
my $num_path_objects = scalar(@path_objects);
print "total path objects $num_path_objects\n";
my %seen;
foreach my $path (@path_objects) {
print $path_fullnames{$path},"\n";
my $any_x_neg = 0;
my $any_y_neg = 0;
my (@x,@y,@n);
foreach my $n ($path->n_start+2 .. 50) {
my ($x,$y) = $path->n_to_xy($n)
or last;
push @x, $x;
push @y, $y;
push @n, $n;
$any_x_neg ||= ($x < 0);
$any_y_neg ||= ($y < 0);
}
next unless $any_x_neg || $any_y_neg;
foreach my $x_axis_pos ($any_y_neg ? -1 : (),
0, 1) {
foreach my $x_axis_neg (($any_y_neg ? (-1) : ()),
0,
($any_x_neg ? (1) : ())) {
foreach my $y_axis_pos ($any_x_neg ? -1 : (),
0, 1) {
foreach my $y_axis_neg ($any_x_neg ? (-1) : (),
0,
($any_y_neg ? (1) : ())) {
my $fullname = $path_fullnames{$path} . " Xpos=$x_axis_pos Xneg=$x_axis_neg Ypos=$y_axis_pos Yneg=$y_axis_neg";
my @values;
my $str = '';
foreach my $i (0 .. $#x) {
if (($x[$i]<=>0) == ($y[$i]<0 ? $y_axis_neg : $y_axis_pos)
&& ($y[$i]<=>0) == ($x[$i]<0 ? $x_axis_neg : $x_axis_pos)
) {
push @values, $n[$i];
$str .= "$n[$i],";
}
}
next unless @values >= 5;
if (my $prev_fullname = $seen{$str}) {
print "$fullname\n";
print "repeat of $prev_fullname";
print "\n";
} else {
if (my $found = stripped_grep($str)) {
print "$fullname\n";
print " (",substr($str,0,20),"...)\n";
print $found;
print "\n";
print "\n";
$seen{$str} = $fullname;
}
}
}
}
}
}
}
exit 0;
}
# sub stripped_grep {
# my ($str) = @_;
# my $find = `fgrep -e $str $ENV{HOME}/OEIS/stripped`;
# my $ret = '';
# foreach my $line (split /\n/, $find) {
# $ret .= "$line\n";
# my ($anum) = ($line =~ /^(A\d+)/) or die;
# $ret .= `zgrep -e ^$anum $ENV{HOME}/OEIS/names.gz`;
# }
# return $ret;
# }
my $stripped;
sub stripped_grep {
my ($str) = @_;
if (! $stripped) {
require File::Map;
my $filename = "$ENV{HOME}/OEIS/stripped";
File::Map::map_file ($stripped, $filename);
print "File::Map file length ",length($stripped),"\n";
}
my $ret = '';
my $pos = 0;
for (;;) {
$pos = index($stripped,$str,$pos);
last if $pos < 0;
my $start = rindex($stripped,"\n",$pos) + 1;
my $end = index($stripped,"\n",$pos);
my $line = substr($stripped,$start,$end-$start);
$ret .= "$line\n";
my ($anum) = ($line =~ /^(A\d+)/);
$anum || die "$anum not found";
$ret .= `zgrep -e ^$anum $ENV{HOME}/OEIS/names.gz`;
$pos = $end;
}
return $ret;
}
#------------------------------------------------------------------------------
# ($inforef, $inforef, ...)
sub parameter_info_list_to_parameters {
my @parameters = ([]);
foreach my $info (@_) {
info_extend_parameters($info,\@parameters);
}
return \@parameters;
}
sub info_extend_parameters {
my ($info, $parameters) = @_;
my @new_parameters;
if ($info->{'name'} eq 'planepath') {
my @strings;
foreach my $choice (@{$info->{'choices'}}) {
# next unless $choice =~ /DiamondSpiral/;
# next unless $choice =~ /Gcd/;
# next unless $choice =~ /LCorn|RationalsTree/;
next unless $choice =~ /dragon/i;
# next unless $choice =~ /SierpinskiArrowheadC/;
# next unless $choice eq 'DiagonalsAlternating';
my $path_class = "Math::PlanePath::$choice";
Module::Load::load($path_class);
my @parameter_info_list = $path_class->parameter_info_list;
{
my $path = $path_class->new;
if (defined $path->{'n_start'}
&& ! $path_class->parameter_info_hash->{'n_start'}) {
push @parameter_info_list,{ name => 'n_start',
type => 'enum',
choices => [0,1],
default => $path->default_n_start,
};
}
}
if ($path_class->isa('Math::PlanePath::Rows')) {
push @parameter_info_list,{ name => 'width',
type => 'integer',
width => 3,
default => '1',
minimum => 1,
};
}
if ($path_class->isa('Math::PlanePath::Columns')) {
push @parameter_info_list, { name => 'height',
type => 'integer',
width => 3,
default => '1',
minimum => 1,
};
}
my $path_parameters
= parameter_info_list_to_parameters(@parameter_info_list);
### $path_parameters
foreach my $aref (@$path_parameters) {
my $str = $choice;
while (@$aref) {
$str .= "," . shift(@$aref) . '=' . shift(@$aref);
}
push @strings, $str;
}
}
### @strings
foreach my $p (@$parameters) {
foreach my $choice (@strings) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'choices'}) {
my @new_parameters;
foreach my $p (@$parameters) {
foreach my $choice (@{$info->{'choices'}}) {
next if ($info->{'name'} eq 'serpentine_type' && $choice eq 'Peano');
next if ($info->{'name'} eq 'rotation_type' && $choice eq 'custom');
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
if ($info->{'name'} eq 'serpentine_type') {
push @new_parameters, [ @$p, $info->{'name'}, '100_000_000' ];
push @new_parameters, [ @$p, $info->{'name'}, '101_010_101' ];
push @new_parameters, [ @$p, $info->{'name'}, '000_111_000' ];
push @new_parameters, [ @$p, $info->{'name'}, '111_000_111' ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'type'} eq 'boolean') {
my @new_parameters;
foreach my $p (@$parameters) {
foreach my $choice (0, 1) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'type'} eq 'integer'
|| $info->{'name'} eq 'multiples') {
my @choices;
if ($info->{'name'} eq 'radix') { @choices = (2,3,10,16); }
if ($info->{'name'} eq 'n_start') { @choices = (0,1); }
if ($info->{'name'} eq 'x_start'
|| $info->{'name'} eq 'y_start') { @choices = ($info->{'default'}); }
if (! @choices) {
my $min = $info->{'minimum'} // -5;
my $max = $min + 10;
if (# $module =~ 'PrimeIndexPrimes' &&
$info->{'name'} eq 'level') { $max = 5; }
# if ($info->{'name'} eq 'arms') { $max = 2; }
if ($info->{'name'} eq 'rule') { $max = 255; }
if ($info->{'name'} eq 'round_count') { $max = 20; }
if ($info->{'name'} eq 'straight_spacing') { $max = 1; }
if ($info->{'name'} eq 'diagonal_spacing') { $max = 1; }
if ($info->{'name'} eq 'radix') { $max = 17; }
if ($info->{'name'} eq 'realpart') { $max = 3; }
if ($info->{'name'} eq 'wider') { $max = 1; }
if ($info->{'name'} eq 'modulus') { $max = 32; }
if ($info->{'name'} eq 'polygonal') { $max = 32; }
if ($info->{'name'} eq 'factor_count') { $max = 12; }
if ($info->{'name'} eq 'diagonal_length') { $max = 5; }
if ($info->{'name'} eq 'height') { $max = 4; }
if ($info->{'name'} eq 'width') { $max = 4; }
if ($info->{'name'} eq 'k') { $max = 4; }
if (defined $info->{'maximum'} && $max > $info->{'maximum'}) {
$max = $info->{'maximum'};
}
if ($info->{'name'} eq 'power' && $max > 6) { $max = 6; }
@choices = ($min .. $max);
}
my @new_parameters;
foreach my $choice (@choices) {
foreach my $p (@$parameters) {
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
@$parameters = @new_parameters;
return;
}
if ($info->{'name'} eq 'fraction') {
### fraction ...
my @new_parameters;
foreach my $p (@$parameters) {
my $radix = p_radix($p) || die;
foreach my $den (995 .. 1021) {
next if $den % $radix == 0;
my $choice = "1/$den";
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
foreach my $num (2 .. 10) {
foreach my $den ($num+1 .. 15) {
next if $den % $radix == 0;
next unless _coprime($num,$den);
my $choice = "$num/$den";
push @new_parameters, [ @$p, $info->{'name'}, $choice ];
}
}
}
@$parameters = @new_parameters;
return;
}
print " skip parameter $info->{'name'}\n";
}
# return true if coprime
sub _coprime {
my ($x, $y) = @_;
### _coprime(): "$x,$y"
if ($y > $x) {
($x,$y) = ($y,$x);
}
for (;;) {
if ($y <= 1) {
### result: ($y == 1)
return ($y == 1);
}
($x,$y) = ($y, $x % $y);
}
}
sub p_radix {
my ($p) = @_;
for (my $i = 0; $i < @$p; $i += 2) {
if ($p->[$i] eq 'radix') {
return $p->[$i+1];
}
}
return undef;
}
__END__
Math-PlanePath-113/devel/run.pl 0000644 0001750 0001750 00000044177 12253223503 014151 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use POSIX qw(floor ceil);
use Math::Libm;
use List::Util qw(min max);
use Module::Load;
use Math::PlanePath::Base::Digits 'round_down_pow';
# uncomment this to run the ### lines
# use Smart::Comments;
{
my $path_class;
$path_class = 'Math::PlanePath::QuadricCurve';
$path_class = 'Math::PlanePath::LTiling';
$path_class = 'Math::PlanePath::TerdragonCurve';
$path_class = 'Math::PlanePath::TerdragonMidpoint';
$path_class = 'Math::PlanePath::SierpinskiArrowhead';
$path_class = 'Math::PlanePath::QuintetCentres';
$path_class = 'Math::PlanePath::HIndexing';
$path_class = 'Math::PlanePath::WunderlichSerpentine';
$path_class = 'Math::PlanePath::R5DragonMidpoint';
$path_class = 'Math::PlanePath::CCurve';
$path_class = 'Math::PlanePath::NxN';
$path_class = 'Math::PlanePath::NxNinv';
$path_class = 'Math::PlanePath::Dispersion';
$path_class = 'Math::PlanePath::KochSquareflakes';
$path_class = 'Math::PlanePath::TerdragonRounded';
$path_class = 'Math::PlanePath::HilbertSpiral';
$path_class = 'Math::PlanePath::GreekKeySpiral';
$path_class = 'Math::PlanePath::ComplexMinus';
$path_class = 'Math::PlanePath::QuintetReplicate';
$path_class = 'Math::PlanePath::GosperReplicate';
$path_class = 'Math::PlanePath::ComplexPlus';
$path_class = 'Math::PlanePath::CubicBase';
$path_class = 'Math::PlanePath::DigitGroups';
$path_class = 'Math::PlanePath::GrayCode';
$path_class = 'Math::PlanePath::ZOrderCurve';
$path_class = 'Math::PlanePath::ImaginaryBase';
$path_class = 'Math::PlanePath::KochCurve';
$path_class = 'Math::PlanePath::PixelRings';
$path_class = 'Math::PlanePath::TriangleSpiral';
$path_class = 'Math::PlanePath::HypotOctant';
$path_class = 'Math::PlanePath::SquareSpiral';
$path_class = 'Math::PlanePath::PowerArray';
$path_class = 'Math::PlanePath::ParabolicRuns';
$path_class = 'Math::PlanePath::DiagonalsOctant';
$path_class = 'Math::PlanePath::PyramidRows';
$path_class = 'Math::PlanePath::Corner';
$path_class = 'Math::PlanePath::ComplexRevolving';
$path_class = 'Math::PlanePath::DragonMidpoint';
$path_class = 'Math::PlanePath::ParabolicRows';
$path_class = 'Math::PlanePath::QuintetCurve';
$path_class = 'Math::PlanePath::TriangularHypot';
$path_class = 'Math::PlanePath::AlternatePaper';
$path_class = 'Math::PlanePath::SierpinskiArrowheadCentres';
$path_class = 'Math::PlanePath::DekkingCentres';
$path_class = 'Math::PlanePath::DekkingCurve';
$path_class = 'Math::PlanePath::DiamondSpiral';
$path_class = 'Math::PlanePath::DragonCurve';
$path_class = 'Math::PlanePath::KochelCurve';
$path_class = 'Math::PlanePath::FibonacciWordFractal';
$path_class = 'Math::PlanePath::CincoCurve';
$path_class = 'Math::PlanePath::WunderlichMeander';
$path_class = 'Math::PlanePath::AR2W2Curve';
$path_class = 'Math::PlanePath::AlternatePaperMidpoint';
$path_class = 'Math::PlanePath::BetaOmega';
$path_class = 'Math::PlanePath::FractionsTree';
$path_class = 'Math::PlanePath::R5DragonCurve';
$path_class = 'Math::PlanePath::GcdRationals';
$path_class = 'Math::PlanePath::Diagonals';
$path_class = 'Math::PlanePath::LToothpickTree';
$path_class = 'Math::PlanePath::CfracDigits';
$path_class = 'Math::PlanePath::BalancedArray';
$path_class = 'Math::PlanePath::FibonacciWordKnott';
$path_class = 'Math::PlanePath::LCornerReplicate';
$path_class = 'Math::PlanePath::HilbertCurve';
$path_class = 'Math::PlanePath::ImaginaryHalf';
$path_class = 'Math::PlanePath::R7DragonCurve';
$path_class = 'Math::PlanePath::GosperIslands';
$path_class = 'Math::PlanePath::ToothpickReplicate';
$path_class = 'Math::PlanePath::EToothpickTree';
$path_class = 'Math::PlanePath::Hypot';
$path_class = 'Math::PlanePath::SierpinskiCurve';
$path_class = 'Math::PlanePath::FlowsnakeCentres';
$path_class = 'Math::PlanePath::Flowsnake';
$path_class = 'Math::PlanePath::LToothpickTree';
$path_class = 'Math::PlanePath::AnvilSpiral';
$path_class = 'Math::PlanePath::FilledRings';
$path_class = 'Math::PlanePath::HexSpiral';
$path_class = 'Math::PlanePath::HexSpiralSkewed';
$path_class = 'Math::PlanePath::TwoOfEightByCells';
$path_class = 'Math::PlanePath::DivisibleColumns';
$path_class = 'Math::PlanePath::CoprimeColumns';
$path_class = 'Math::PlanePath::DiagonalRationals';
$path_class = 'Math::PlanePath::PeninsulaBridge';
$path_class = 'Math::PlanePath::PowerRows';
$path_class = 'Math::PlanePath::WythoffDifference';
$path_class = 'Math::PlanePath::WythoffTriangle';
$path_class = 'Math::PlanePath::WythoffArray';
$path_class = 'Math::PlanePath::UlamWarburtonQuarter';
$path_class = 'Math::PlanePath::SumFractions';
$path_class = 'Math::PlanePath::AztecDiamondRings';
$path_class = 'Math::PlanePath::TriangleSpiralSkewed';
$path_class = 'Math::PlanePath::PeanoCurve';
$path_class = 'Math::PlanePath::CellularRule190';
$path_class = 'Math::PlanePath::CellularRule54';
$path_class = 'Math::PlanePath::CellularRule';
$path_class = 'Math::PlanePath::PeanoVertices';
$path_class = 'Math::PlanePath::OneOfEightByCells';
$path_class = 'Math::PlanePath::OneOfEight';
$path_class = 'Math::PlanePath::ZeckendorfTerms';
$path_class = 'Math::PlanePath::BinaryTerms';
$path_class = 'Math::PlanePath::LCornerTreeByCells';
$path_class = 'Math::PlanePath::UlamWarburtonOld';
$path_class = 'Math::PlanePath::UlamWarburton';
$path_class = 'Math::PlanePath::LCornerTree';
$path_class = 'Math::PlanePath::ToothpickSpiral';
$path_class = 'Math::PlanePath::SierpinskiTriangle';
$path_class = 'Math::PlanePath::ChanTree';
$path_class = 'Math::PlanePath::RationalsTree';
$path_class = 'Math::PlanePath::PyramidSpiral';
$path_class = 'Math::PlanePath::CornerReplicate';
$path_class = 'Math::PlanePath::WythoffPreliminaryTriangle';
$path_class = 'Math::PlanePath::WythoffLines';
$path_class = 'Math::PlanePath::OctagramSpiral';
$path_class = 'Math::PlanePath::MPeaks';
$path_class = 'Math::PlanePath::KnightSpiral';
$path_class = 'Math::PlanePath::PentSpiralSkewed';
$path_class = 'Math::PlanePath::PentSpiral';
$path_class = 'Math::PlanePath::HeptSpiralSkewed';
$path_class = 'Math::PlanePath::FourReplicate';
$path_class = 'Math::PlanePath::DiagonalsAlternating';
$path_class = 'Math::PlanePath::ToothpickTreeByCells';
$path_class = 'Math::PlanePath::ToothpickTree';
$path_class = 'Math::PlanePath::FactorRationals';
$path_class = 'Math::PlanePath::MultipleRings';
$path_class = 'Math::PlanePath::HTreeByCells';
$path_class = 'Math::PlanePath::ToothpickUpist';
$path_class = 'Math::PlanePath::HTree';
$path_class = 'Math::PlanePath::PythagoreanTree';
my $lo = 0;
my $hi = 41;
Module::Load::load($path_class);
my $path = $path_class->new
(
coordinates => 'PQ',
tree_type => 'UAD',
# ring_shape => 'polygon',
# step => 1,
# sign_encoding => 'revbinary',
# n_start => 0,
# parts => 'wedge',
# shift => 6,
# pn_encoding => 'negabinary',
# points => 'all_mul',
# k => 4,
# digit_order => 'HtoL',
# digit_order => 'LtoH',
# reduced => 1,
#radix => 4,
# parts => 'wedge+1',
# rule => 6,
# align => 'down',
# x_start => 5,
# y_start => 2,
# divisor_type => 'proper',
# wider => 3,
# reverse => 1,
# tree_type => 'L',
# arms => 2,
# sides=>3,
# digit_order => 'XnYX',
# radix => 2,
# points => 'square_centred',
# pairs_order => 'rows_reverse',
# pairs_order => 'diagonals_up',
# tree_type => 'HCS',
# start => 'snowflake',
# n_start=>37,
# step => 5,
# n_start => 37,
# align => 'diagonal',
# offset => -0.5,
# turns => 1,
# base => 7,
# direction => 'up',
# diagonal_length => 5,
# apply_type => 'FS',
# serpentine_type => '010_000',
# straight_spacing => 3,
# diagonal_spacing => 7,
# arms => 7,
# wider => 3,
# realpart => 1,
# mirror => 1,
);
### $path
my %seen;
my $n_start = $path->n_start;
my $arms_count = $path->arms_count;
my $path_ref = ref($path);
print "n_start()=$n_start arms_count()=$arms_count $path_ref\n";
{
my $num_roots = $path->tree_num_roots();
my @n_list = $path->tree_root_n_list();
print " $num_roots roots n=",join(',',@n_list),"\n";
}
{
require Data::Float;
my $pos_infinity = Data::Float::pos_infinity();
my $neg_infinity = Data::Float::neg_infinity();
my $nan = Data::Float::nan();
$path->n_to_xy($pos_infinity);
$path->n_to_xy($neg_infinity);
$path->n_to_xy($nan);
$path->xy_to_n(0,$pos_infinity);
$path->xy_to_n(0,$neg_infinity);
$path->xy_to_n(0,$nan);
$path->xy_to_n($pos_infinity,0);
$path->xy_to_n($neg_infinity,0);
$path->xy_to_n($nan,0);
$path->rect_to_n_range($pos_infinity,0,0,0);
$path->rect_to_n_range($neg_infinity,0,0,0);
$path->rect_to_n_range($nan,0,0,0);
$path->rect_to_n_range(0,$pos_infinity,0,0);
$path->rect_to_n_range(0,$neg_infinity,0,0);
$path->rect_to_n_range(0,$nan,0,0);
}
for (my $i = $n_start+$lo; $i <= $hi; $i+=1) {
#for (my $i = $n_start; $i <= $n_start + 800000; $i=POSIX::ceil($i*2.01+1)) {
my ($x, $y) = $path->n_to_xy($i) or next;
# next unless $x < 0; # abs($x)>abs($y) && $x > 0;
my $dxdy = '';
my $diffdxdy = '';
my ($dx, $dy) = $path->n_to_dxdy($i);
if (defined $dx && defined $dy) {
my $d = Math::Libm::hypot($dx,$dy);
$dxdy = sprintf "%.3f,%.3f(%.3f)", $dx,$dy,$d;
} else {
$dxdy='[undef]';
}
my ($next_x, $next_y) = $path->n_to_xy($i+$arms_count);
if (defined $next_x && defined $next_y) {
my $want_dx = $next_x - $x;
my $want_dy = $next_y - $y;
if ($dx != $want_dx || $dy != $want_dy) {
$diffdxdy = "dxdy(want $want_dx,$want_dy)";
}
}
my $rep = '';
my $xy = (defined $x ? $x : 'undef').','.(defined $y ? $y : 'undef');
if (defined $seen{$xy}) {
$rep = "rep$seen{$xy}";
$seen{$xy} .= ",$i";
} else {
$seen{$xy} = $i;
}
my @n_list = $path->xy_to_n_list ($x+.0, $y-.0);
my $n_rev;
if (@n_list) {
$n_rev = join(',',@n_list);
} else {
$n_rev = 'norev';
}
my $rev = '';
if (@n_list && $n_list[0] ne $seen{$xy}) {
$rev = 'Rev';
}
my ($n_lo, $n_hi) = $path->rect_to_n_range ($x,$y, $x,$y);
my $range = '';
if ($n_hi < $i || $n_lo > $i) {
$range = 'Range';
}
my $n_children = '';
my @n_children = $path->tree_n_children ($i);
if (@n_children) {
$n_children = " c=";
foreach my $n_child (@n_children) {
my $n_parent = $path->tree_n_parent($n_child);
if (! defined $n_parent || $n_parent != $i) {
$n_children .= "***";
}
$n_children .= $n_child;
$n_children .= ",";
}
$n_children =~ s/,$//;
}
my $num_children = $path->tree_n_num_children($i);
if (! defined $num_children || $num_children != scalar(@n_children)) {
$n_children .= "numchildren***";
}
my $depth = $path->tree_n_to_depth($i);
if (defined $depth) {
$n_children .= " d=$depth";
}
my $baddepth = '';
if ($path->can('tree_n_to_depth')
!= Math::PlanePath->can('tree_n_to_depth')) {
my $depth = $path->tree_n_to_depth($i);
my $calc_depth = path_tree_n_to_depth_by_parents($path,$i);
if (! defined $depth || $calc_depth != $depth) {
$baddepth .= "ntodepth=$depth,parentcalc=$calc_depth";
}
}
my $flag = '';
if ($rev || $range || $diffdxdy || $baddepth) {
$flag .= " ***$rev$range$diffdxdy$baddepth";
}
if (! defined $n_lo) { $n_lo = 'undef'; }
if (! defined $n_hi) { $n_hi = 'undef'; }
my $iwidth = ($i == int($i) ? 0 : 2);
printf "%.*f %7.3f,%7.3f %3s %s %s%s %s %s\n",
$iwidth,$i, $x,$y,
$n_rev,
"${n_lo}_${n_hi}",
$dxdy,
$n_children,
" $rep",
$flag;
# %.2f ($x*$x+$y*$y),
}
exit 0;
}
sub path_tree_n_to_depth_by_parents {
my ($path, $n) = @_;
if ($n < $path->n_start) {
return undef;
}
my $depth = 0;
for (;;) {
my $parent_n = $path->tree_n_parent($n);
last if ! defined $parent_n;
if ($parent_n >= $n) {
warn "Oops, tree parent $parent_n >= child $n in ", ref $path;
return -1;
}
$n = $parent_n;
$depth++;
}
return $depth;
}
__END__
{
use Math::PlanePath::KochCurve;
package Math::PlanePath::KochCurve;
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
$y1 = round_nearest ($y1);
$y2 = round_nearest ($y2);
if ($y1 > $y2) { ($y1,$y2) = ($y2,$y1) }
if ($y2 < 0) {
return (1,0);
}
$x1 = round_nearest ($x1);
$x2 = round_nearest ($x2);
if ($x1 > $x2) { ($x1,$x2) = ($x2,$x1) }
### rect_to_n_range(): "$x1,$y1 $x2,$y2"
my (undef, $top_level) = round_down_pow (max(2, abs($x1), abs($x2)),
3);
$top_level += 2;
### $top_level
my ($tx,$ty, $dir, $len);
my $intersect_rect_p = sub {
if ($dir < 0) {
$dir += 6;
} elsif ($dir > 5) {
$dir -= 6;
}
my $left_x = $tx;
my $peak_y = $ty;
my $offset;
if ($dir & 1) {
# pointing downwards
if ($dir == 1) {
$left_x -= $len-1; # +1 to exclude left edge
$peak_y += $len;
} elsif ($dir == 3) {
$left_x -= 2*$len;
} else {
$peak_y++; # exclude top edge
}
if ($peak_y < $y1) {
### all below ...
return 0;
}
$offset = $y2 - $peak_y;
} else {
# pointing upwards
if ($dir == 2) {
$left_x -= 2*$len;
} elsif ($dir == 4) {
$left_x -= $len;
$peak_y -= $len-1; # +1 exclude bottom edge
}
if ($peak_y > $y2) {
### all above ...
return 0;
}
$offset = $peak_y - $y1;
}
my $right_x = $left_x + 2*($len-1);
if ($offset > 0) {
$left_x += $offset;
$right_x -= $offset;
}
### $offset
### $left_x
### $right_x
### result: ($left_x <= $x2 && $right_x >= $x1)
return ($left_x <= $x2 && $right_x >= $x1);
};
my @pending_tx = (0);
my @pending_ty = (0);
my @pending_dir = (0);
my @pending_level = ($top_level);
my @pending_n = (0);
my $n_lo;
for (;;) {
if (! @pending_tx) {
### nothing in rectangle for low ...
return (1,0);
}
$tx = pop @pending_tx;
$ty = pop @pending_ty;
$dir = pop @pending_dir;
my $level = pop @pending_level;
my $n = pop @pending_n;
$len = 3**$level;
### pop for low ...
### n: sprintf('0x%X',$n)
### $level
### $len
### $tx
### $ty
### $dir
unless (&$intersect_rect_p()) {
next;
}
$level--;
if ($level < 0) {
$n_lo = $n;
last;
}
$n *= 4;
$len = 3**$level;
### descend: "len=$len"
push @pending_tx, $tx+4*$len;
push @pending_ty, $ty;
push @pending_dir, $dir;
push @pending_level, $level;
push @pending_n, $n+3;
push @pending_tx, $tx+3*$len;
push @pending_ty, $ty;
push @pending_dir, $dir-1;
push @pending_level, $level;
push @pending_n, $n+2;
push @pending_tx, $tx+2*$len;
push @pending_ty, $ty;
push @pending_dir, $dir+1;
push @pending_level, $level;
push @pending_n, $n+1;
push @pending_tx, $tx;
push @pending_ty, $ty;
push @pending_dir, $dir;
push @pending_level, $level;
push @pending_n, $n;
}
### high ...
@pending_tx = (0);
@pending_ty = (0);
@pending_dir = (0);
@pending_level = ($top_level);
@pending_n = (0);
for (;;) {
if (! @pending_tx) {
### nothing in rectangle for high ...
return (1,0);
}
$tx = pop @pending_tx;
$ty = pop @pending_ty;
$dir = pop @pending_dir;
my $level = pop @pending_level;
my $n = pop @pending_n;
### pop for high ...
### n: sprintf('0x%X',$n)
### $level
### $len
### $tx
### $ty
### $dir
$len = 3**$level;
unless (&$intersect_rect_p()) {
next;
}
$level--;
if ($level < 0) {
return ($n_lo, $n);
}
$n *= 4;
$len = 3**$level;
### descend
push @pending_tx, $tx;
push @pending_ty, $ty;
push @pending_dir, $dir;
push @pending_level, $level;
push @pending_n, $n;
push @pending_tx, $tx+2*$len;
push @pending_ty, $ty;
push @pending_dir, $dir+1;
push @pending_level, $level;
push @pending_n, $n+1;
push @pending_tx, $tx+3*$len;
push @pending_ty, $ty;
push @pending_dir, $dir-1;
push @pending_level, $level;
push @pending_n, $n+2;
push @pending_tx, $tx+4*$len;
push @pending_ty, $ty;
push @pending_dir, $dir;
push @pending_level, $level;
push @pending_n, $n+3;
}
}
}
{
require Math::PlanePath::KochSnowflakes;
my $path = Math::PlanePath::KochSnowflakes->new;
my @range = $path->rect_to_n_range (0,0, 0,2);
### @range
exit 0;
}
{
require Math::PlanePath::PixelRings;
my $path = Math::PlanePath::PixelRings->new
(wider => 0,
# step => 0,
#tree_type => 'UAD',
#coordinates => 'PQ',
);
### xy: $path->n_to_xy(500)
### n: $path->xy_to_n(3,3)
exit 0;
}
Math-PlanePath-113/devel/archimedean.pl 0000644 0001750 0001750 00000023142 12000752040 015563 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::Libm 'hypot', 'asinh', 'M_PI', 'asin';
use POSIX ();
use Math::PlanePath::Base::Generic 'round_nearest';
use Math::PlanePath::ArchimedeanChords;
# uncomment this to run the ### lines
use Smart::Comments;
# set term x
# plot [0:50] asinh(x),exp(log(x)*.4)
{
for (my $r = 1; $r < 1e38; $r *= 1.1) {
my $theta = $r * 2*M_PI();
my $arc = spiral_arc_length($theta);
my $circle = r_to_circles_arclength($r);
# $circle = ($r*$r+1)*M_PI; # maybe
printf "%2d %10.3g %10.3g %.3f\n",
$r,
$circle,
$arc,
($circle<$arc);
}
exit 0;
}
# 1/4pi * (t * sqrt(1+t^2) + log(t+sqrt(1+t^2)))
#
# sqrt(1+t^2) <= t + 1/(2*t)
#
# 1/4pi * (t * sqrt(1+t^2) + asinh(t))
# <= 1/4pi * (t*(t+1/2t) + asinh(t))
# = 1/4pi * (2pi*r * (2pi*r+ 1/(4pi*r)) + asinh(2pi*r))
# = 1/2 * r * (2pi*r + 1/(4pi*r)) + 1/4pi * asinh(2pi*r))
# = pi * r * (r + 1/(8pi^2*r)) + 1/4pi * asinh(2pi*r))
# = pi * (r^2 + 1/8pi^2*r) + 1/4pi * asinh(2pi*r))
{
sub r_to_circles_arclength {
my ($r) = @_;
return M_PI()*$r*($r+1);
}
sub spiral_arc_length {
my ($theta) = @_; # theta in radians
return (1/(4*M_PI())) * ($theta * sqrt(1+$theta**2) + asinh($theta));
# with $a = 1/2pi for unit spacing
# return 0.5 * $a * ($theta * sqrt(1+$theta**2) + asinh($theta));
}
sub total_chords {
my ($r) = @_;
my $sum = 0;
foreach my $i (2 .. POSIX::ceil($r)) {
$sum += circle_chords($i);
}
return $sum;
}
my $a = 1 / (2*M_PI());
print "a=$a\n";
print "r=",(2*M_PI)*$a,"\n";
for (my $r = 1; $r < 1e38; $r *= 1.5) {
my $theta = $r * 2*M_PI();
my $arc = spiral_arc_length($theta);
my $circle = r_to_circles_arclength($r);
$circle = ($r*$r+1)*M_PI;
my $chords = total_chords($r-1);
printf "%2d %10.3g %10.3g %10.3g %.3f\n",
$r,
$chords,
$circle,
$arc,
($circle-$arc)/$r;
}
exit 0;
}
{
require Math::Polynomial;
require Math::BigRat;
my $asin = Math::Polynomial->new (map
# {Math::BigRat->new($_)}
{eval $_}
0, 1,
0, '1/6',
0, '3/40',
0, '5/112',
0, '35/1152');
$asin->string_config({ascending=>1});
print "$asin\n";
my $r2 = $asin->new (0, 0.5);
my $den = $asin->nest($r2);
print "$den\n";
my $num = $asin->monomial(1);
foreach (1 .. 40) {
(my $q, $num) = $num->divmod($den);
print "q=$q\n";
$num = $num->shift_up(1);
}
exit 0;
}
{
sub circle_chords {
my ($r) = @_;
return M_PI() / asin(0.5/$r);
}
for (my $r = 1; $r < 100; $r++) {
my $chords = circle_chords($r);
printf "%2d %8.3g\n",
$r, $chords;
}
exit 0;
}
{
my $path = Math::PlanePath::ArchimedeanChords->new;
my $prev_x = 1;
my $prev_n = 0;
my $i = 0;
foreach my $n ($path->n_start .. 100000) {
my ($x, $y) = $path->n_to_xy ($n);
if ($x > 0 && $prev_x < 0) {
$i++;
my $diff = $n - $prev_n;
my $avg = $diff / $i;
print "$n $diff $avg\n";
$prev_n = $n;
}
$prev_x = $x;
}
exit 0;
}
{
require Math::PlanePath::ArchimedeanChords;
require Math::PlanePath::TheodorusSpiral;
require Math::PlanePath::VogelFloret;
#my $path = Math::PlanePath::VogelFloret->new;
my $path = Math::PlanePath::ArchimedeanChords->new;
### $path
my $n = $path->xy_to_n (600, 0);
### $n
$n = $path->xy_to_n (600, 0);
### $n
exit 0;
}
{
require Math::Symbolic;
use Math::Symbolic::Derivative;
my $tree = Math::Symbolic->parse_from_string(
# '(t*cos(t)-c)^2'
# '(t*sin(t)-s)'
# '(t+1)^2'
# '(t+u)^2 + t^2'
'(t+u)*cos(u)'
);
# my $tree = Math::Symbolic->parse_from_string();
print "$tree\n";
my $derived = Math::Symbolic::Derivative::total_derivative($tree, 'u');
$derived = $derived->simplify;
print "$derived\n";
exit 0;
}
# sub _chord_length {
# my ($t1, $t2) = @_;
# my $hyp = hypot(1,$theta);
# return 0.5 * _A * ($theta*$hyp + asinh($theta));
# }
sub step {
my ($x, $y) = @_;
my $r = hypot($x,$y);
my $len = 1/$r;
my ($x2, $y2);
foreach (1 .. 5) {
($x2,$y2) = ($x - $y*$len, $y + $x*$len);
# atan($y2,$x2)
my $f = hypot($x-$x2, $y-$y2);
$len /= $f;
### maybe: "$x2,$y2 $f"
}
return ($x2, $y2);
}
sub next_t {
my ($t1, $prev_dt) = @_;
my $t = $t1;
# my $c1 = $t1 * cos($t1);
# my $s1 = $t1 * sin($t1);
# my $c1_2 = $c1*2;
# my $s1_2 = $s1*2;
# my $t1sqm = $t1*$t1 - 4*M_PI()*M_PI();
my $u = 2*M_PI()/$t;
printf "estimate u=%.6f\n", $u;
foreach (0 .. 10) {
# my $slope = 2*($t + (-$c1-$s1*$t)*cos($t) + ($c1*$t-$s1)*sin($t));
# my $f = ( ($t*cos($t) - $c1) ** 2
# + ($t*sin($t) - $s1) ** 2
# - 4*M_PI()*M_PI() );
# my $slope = (2*($t*cos($t)-$c1)*(cos($t) - $t*sin($t))
# + 2*($t*sin($t)-$s1)*(sin($t) + $t*cos($t)));
my $f = ($t+$u)**2 + $t**2 - 2*$t*($t+$u)*cos($u) - 4*M_PI()*M_PI();
my $slope = 2 * ( $t*(1-cos($u)) + $u + $t*($t+$u)*sin($u) );
my $sub = $f/$slope;
$u -= $sub;
# my $ct = cos($t);
# my $st = sin($t);
# my $f = (($t - $ct*$c1_2 - $st*$s1_2) * $t + $t1sqm);
# my $slope = 2 * (($t*$ct - $c1) * ($ct - $t*$st)
# + ($t*$st - $s1) * ($st + $t*$ct));
# my $sub = $f/$slope;
# $t -= $sub;
last if ($sub < 1e-15);
printf ("h=%.6f d=%.6f sub=%.20f u=%.6f\n", $slope, $f, $sub, $u);
}
return $t + $u;
}
{
my $t = 2*M_PI;
my $prev_dt = 1;
my $prev_x = 1;
my $prev_y = 0;
foreach (1 .. 50) {
my $nt = next_t($t,$prev_dt);
my $prev_dt = $nt - $t;
$t = $nt;
my $r = $t * (1 / (2*M_PI()));
my $x = $r*cos($t);
my $y = $r*sin($t);
my $d = hypot($x-$prev_x, $y-$prev_y);
my $pdest = 2*M_PI()/$t;
printf "%d t=%.6f d=%.3g pdt=%.3f/%.3f\n",
$_, $t, $d-1, $prev_dt, $pdest;
$prev_x = $x;
$prev_y = $y;
}
exit 0;
}
{
my $t1 = 1 * 2*M_PI;
my $t = $t1;
my $r1 = $t / (2*M_PI);
my $c = cos($t);
my $s = sin($t);
my $c1 = $t1 * cos($t1);
my $s1 = $t1 * sin($t1);
my $c1_2 = $c1*2;
my $s1_2 = $s1*2;
my $t1sqm = $t1*$t1 - 4*M_PI()*M_PI();
my $x1 = $r1*cos($t1);
my $y1 = $r1*sin($t1);
print "x1=$x1 y1=$y1\n";
$t += 1;
# {
# my $r2 = $t / (2*M_PI);
# my $dist = ($t1*cos($t1) - $t*cos($t) ** 2
# + ($t1*sin($t1) - $t*sin($t)) ** 2
# - 4*M_PI()*M_PI());
# my $slope = (2*($t*cos($t)-$c1)*(cos($t) - $t*sin($t))
# + 2*($t*sin($t)-$s1)*(sin($t) + $t*cos($t)));
# # my $slope = 2*($t + (-$c1-$s1*$t)*cos($t) + ($c1*$t-$s1)*sin($t));
# printf "d=%.6f slope=%.6f 1/slope=%.6f\n", $dist, $slope, 1/$slope;
# }
foreach (0 .. 10) {
# my $slope = 2*($t + (-$c1-$s1*$t)*cos($t) + ($c1*$t-$s1)*sin($t));
# my $dist = ( ($t*cos($t) - $c1) ** 2
# + ($t*sin($t) - $s1) ** 2
# - 4*M_PI()*M_PI() );
# my $slope = (2*($t*cos($t)-$c1)*(cos($t) - $t*sin($t))
# + 2*($t*sin($t)-$s1)*(sin($t) + $t*cos($t)));
my $ct = cos($t);
my $st = sin($t);
my $dist = (($t - $ct*$c1_2 - $st*$s1_2) * $t + $t1sqm);
my $slope = 2 * (($t*$ct - $c1) * ($ct - $t*$st)
+ ($t*$st - $s1) * ($st + $t*$ct));
my $sub = $dist/$slope;
$t -= $sub;
printf ("h=%.6f d=%.6f sub=%.20f t=%.6f\n", $slope, $dist, $sub, $t);
}
my $r2 = $t / (2*M_PI);
my $x2 = $r2 * cos($t);
my $y2 = $r2 * sin($t);
my $dist = hypot ($x1-$x2, $y1-$y2);
printf ("d=%.6f dt=%.6f\n", $dist, $t - $t1);
exit 0;
}
{
my ($x, $y) = (1, 0);
foreach (1 .. 3) {
step ($x, $y);
### step to: "$x, $y"
}
exit 0;
}
{
my $width = 79;
my $height = 40;
my $x_scale = 3;
my $y_scale = 2;
my $y_origin = int($height/2);
my $x_origin = int($width/2);
my $path = Math::PlanePath::ArchimedeanChords->new;
my @rows = (' ' x $width) x $height;
foreach my $n (0 .. 60) {
my ($x, $y) = $path->n_to_xy ($n) or next;
$x *= $x_scale;
$y *= $y_scale;
$x += $x_origin;
$y = $y_origin - $y; # inverted
$x -= length($n) / 2;
$x = round_nearest ($x);
$y = round_nearest ($y);
if ($x >= 0 && $x < $width && $y >= 0 && $y < $height) {
substr ($rows[$y], $x,length($n)) = $n;
}
}
foreach my $row (@rows) {
print $row,"\n";
}
exit 0;
}
{
foreach my $i (0 .. 50) {
my $theta = Math::PlanePath::ArchimedeanChords::_inverse($i);
my $length = Math::PlanePath::ArchimedeanChords::_arc_length($theta);
printf "%2d %8.3f %8.3f\n", $i, $theta, $length;
}
exit 0;
}
Math-PlanePath-113/devel/square-spiral.gnuplot 0000644 0001750 0001750 00000007337 12026721454 017215 0 ustar gg gg #!/usr/bin/gnuplot
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# http://rosettacode.org/wiki/Spiral_matrix
# http://rosettacode.org/wiki/Zig-zag_matrix
# set terminal png
# set terminal xterm
n_to_xy(n) = \
(n <= 1 ? n : nd_to_xy(n, n_to_d(n)))
nd_to_xy(n,d) = \
drem_to_xy(d, n - d_to_base(d))
n_to_d(n) = int ((2 + sqrt(int(4*n))) / 4)
d_to_base(d) = 4 * d**2
# right vertical
# top horizontal
# left vertical
# bottom horizontal
#
drem_to_xy(d,r) = \
(r < -2*d ? d + (r+3*d)*{0,1} \
: r < 0 ? -r + d*{-1,1} \
: r < 2*d ? -d + (d-r)*{0,1} \
: r-2*d + d*{-1,-1})
print n_to_d(0)
print n_to_d(1)
print n_to_d(2)
print n_to_d(3)
print n_to_d(4)
print n_to_d(5)
print ''
print n_to_xy(0)
print n_to_xy(1)
print n_to_xy(2)
print n_to_xy(3)
print n_to_xy(4)
print n_to_xy(5)
print n_to_xy(6)
print n_to_xy(7)
print n_to_xy(8)
print n_to_xy(9)
# set xrange [0:36]
# plot real(n_to_xy(x))
# pause 100
# set xrange [0:36]
# plot x-d_to_base(n_to_d(x))
# pause 100
length=49
set trange [0:length]
set samples 5*length+1
set parametric
set key off
plot real(n_to_xy(t)),imag(n_to_xy(t)) with labels
pause 100
# # Return the position of the highest 1-bit in n.
# # The least significant bit is position 0.
# # For example n=13 is binary "1101" and the high bit is pos=3.
# # If n==0 then the return is 0.
# # Arranging the test as n>=2 avoids infinite recursion if n==NaN (any
# # comparison involving NaN is always false).
# #
# high_bit_pos(n) = (n>=2 ? 1+high_bit_pos(int(n/2)) : 0)
#
# # Return 0 or 1 for the bit at position "pos" in n.
# # pos==0 is the least significant bit.
# #
# bit(n,pos) = int(n / 2**pos) & 1
#
# # dragon(n) returns a complex number which is the position of the
# # dragon curve at integer point "n". n=0 is the first point and is at
# # the origin {0,0}. Then n=1 is at {1,0} which is x=1,y=0, etc. If n
# # is not an integer then the point returned is for int(n).
# #
# # The calculation goes by bits of n from high to low. Gnuplot doesn't
# # have iteration in functions, but can go recursively from
# # pos=high_bit_pos(n) down to pos=0, inclusive.
# #
# # mul() rotates by +90 degrees (complex "i") at bit transitions 0->1
# # or 1->0. add() is a vector (i+1)**pos for each 1-bit, but turned by
# # factor "i" when in a "reversed" section of curve, which is when the
# # bit above is also a 1-bit.
# #
# dragon(n) = dragon_by_bits(n, high_bit_pos(n))
# dragon_by_bits(n,pos) \
# = (pos>=0 ? add(n,pos) + mul(n,pos)*dragon_by_bits(n,pos-1) : 0)
#
# add(n,pos) = (bit(n,pos) ? (bit(n,pos+1) ? {0,1} * {1,1}**pos \
# : {1,1}**pos) \
# : 0)
# mul(n,pos) = (bit(n,pos) == bit(n,pos+1) ? 1 : {0,1})
#
# # Plot the dragon curve from 0 to "length" with line segments.
# # "trange" and "samples" are set so the parameter t runs through
# # integers t=0 to t=length inclusive.
# #
# # Any trange works, it doesn't have to start at 0. But must have
# # enough "samples" that all integers t in the range are visited,
# # otherwise vertices in the curve would be missed.
# #
Math-PlanePath-113/devel/rationals-tree.pl 0000644 0001750 0001750 00000115442 12243053552 016274 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use POSIX ();
use List::Util 'sum';
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh',
'digit_join_lowtohigh';
use Math::PlanePath::RationalsTree;
# uncomment this to run the ### lines
use Smart::Comments;
{
# X,Y list CW
# 1,1,3, 5,11,21,43
# 1,2,5,10,21,42,85
# P = X+Y Q=X X=Q Y=P-Q
#
# X,Y X+Y,X
# / \ / \
# X,(X+Y) (X+Y),Y 2X+Y,X X+2Y,X+Y
# / \ / \ / \ / \
# X,(2X+Y) 2X+Y,X+Y X+Y,X+2Y X+2Y,Y 3X+Y,2X+Y 3X+2Y,2X+Y 2X+3Y,X+Y X+3Y,X+2Y
#
# 1,1
# 1,2 2,1
# 1,3 3,2 2,3 3,1
# 1/4 4/3 3/5 5/2 2/5 5/3 3/4 4/1
#
# X+Y,X 2,1 T
# 3,1 3,2*U
# 4,1*D 5,3 5,2*A 4,3*UU
# 5,1 7,4*DU 8,3*UA 7,5 7,2*UD 8,5*AU 7,3 5,4*UUU
#
# 6,1*DD 9,5 11,4* 10,7* 11,3 13,8* 12,5*AA 9,7 9,2*AD 12,7* 13,5 11,8* 10,3* 11,7 9,4*DA 6,5*
#
# X+Y,Y 2,1 T
# 3,2*U 3,1
# 4,3*UU 5,2 5,3*A 4,1*D
# 5,4*UUU 7,3*DU 8,5*UA 7,2 7,5*UD 8,3*AU 7,4 5,1*UUU
#
# 6,5*DD 9,4 11,4* 10,7* 11,3 13,8* 12,5*AA 9,7 9,2*AD 12,7* 13,8 11,3* 10,7* 11,4* 9,5*DA 6,1*
require Math::PlanePath::RationalsTree;
require Math::PlanePath::PythagoreanTree;
my $pythag = Math::PlanePath::PythagoreanTree->new (coordinates=>'PQ');
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'CW');
my $oe_total = 0;
foreach my $depth (0 .. 6) {
my $oe = 0;
foreach my $n ($path->tree_depth_to_n($depth) ..
$path->tree_depth_to_n_end($depth)) {
my ($x,$y) = $path->n_to_xy($n);
my $flag = '';
($x,$y) = ($x+$y, $y);
if ($x%2 != $y%2) {
$flag = ($x%2?'odd':'even').','.($y%2?'odd':'even');
$oe += $flag ? 1 : 0;
}
my $octant = '';
if ($y < $x) {
$octant = 'octant';
}
my $pn = $pythag->xy_to_n($x,$y);
if ($pn) {
$pn = n_to_pythagstr($pn);
}
printf "N=%2d %2d / %2d %10s %10s %s\n", $n, $x,$y,
$flag, $octant, $pn||'';
$n++;
}
$oe_total += $oe;
print "$oe $oe_total\n";
}
sub n_to_pythagstr {
my ($n) = @_;
if ($n < 1) { return undef; }
my ($pow, $exp) = round_down_pow (2*$n-1, 3);
$n -= ($pow+1)/2; # offset into row
my @digits = digit_split_lowtohigh($n,3);
push @digits, (0) x ($exp - scalar(@digits)); # high pad to $exp many
return '1-'.join('',reverse @digits);
}
exit 0;
}
{
# CW successively per Moshe Newman
require Math::PlanePath::GcdRationals;
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'CW');
my $p = 0;
my $q = 1;
foreach my $n (0 .. 30) {
my ($x,$y) = $path->n_to_xy($n);
$x ||= 0;
$y ||= 0;
my $diff = ($x!=$p || $y!=$q ? ' ***' : '');
print "$n $x,$y $p,$q$diff\n";
# f*q + r = p
# f*q = p - r
# q-r = 1 - (-p % q)
# next = 1 / (2*floor(p/q) + 1 - p/q)
# = q / (2*q*floor(p/q) + q - p)
# = q / (2*q*f + q - p)
# = q / (2*(p - r) + q - p)
# = q / (2*p - 2*r + q - p)
# = q / (p + q - 2*r)
my ($f,$r) = Math::PlanePath::_divrem($p,$q);
# ($p,$q) = ($q, ($q*(2*$f+1) - $p));
($p,$q) = ($q, $p + $q - 2*($p % $q));
# ($p,$q) = ($q, $p-$r + 1 - (-$p % $q));
# my $g = Math::PlanePath::GcdRationals::_gcd($p,$q);
# $p /= $g;
# $q /= $g;
}
exit 0;
}
{
# Pythagorean N search
# CW A016789 3n+2.
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $add (0 .. 3, -3 .. -1) {
print "offset=$add\n";
foreach my $tree_type (@$tree_type_aref) {
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
my @values;
for (my $n = 2; @values < 40; $n += 1) {
my ($x,$y) = $path->n_to_xy($n);
# next unless xy_is_pythagorean($x,$y);
# next unless (($x^$y)&1) == 0; # odd/odd
# next unless (($x^$y)&1) == 1; # odd/even or even/odd
next unless ($x%2==1 && $y%2==0);
push @values, $n+$add;
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values,
name => "$tree_type plus $add");
}
}
exit 0;
sub xy_is_pythagorean {
my ($x,$y) = @_;
return ($x>$y && ($x%2)!=($y%2));
}
}
{
# Pythagorean N in binary
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $tree_type (@$tree_type_aref) {
print "$tree_type\n";
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
for (my $n = 2; $n < 70; $n += 1) {
my ($x,$y) = $path->n_to_xy($n);
next unless xy_is_pythagorean($x,$y);
# next unless (($x^$y)&1) == 0; # odd/odd
# next unless (($x^$y)&1) == 1; # odd/even or even/odd
# next unless ($x%2==1 && $y%2==0);
printf "%7b\n", $n;
}
print "\n";
}
exit 0;
}
{
# X=1 or Y=1 row/column in binary
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $tree_type (@$tree_type_aref) {
{
print "$tree_type Y=1 row\n";
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
for (my $i = 2; $i < 20; $i += 1) {
my $n = $path->xy_to_n($i,1);
printf "%20b\n", $n;
}
print "\n";
}
{
print "$tree_type X=1 row\n";
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
for (my $i = 2; $i < 20; $i += 1) {
my $n = $path->xy_to_n(1,$i);
printf "%20b\n", $n;
}
print "\n";
}
}
exit 0;
}
{
# lamplighter
require Math::NumSeq::OEIS::File;
my $lamp = Math::NumSeq::OEIS::File->new(anum=>'A154435');
my $n = 0b1000001000;
my $l = $lamp->ith($n);
printf "%d %b = %d\n", $n, $l, $l;
exit 0;
}
{
# parity search
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $mult (1,2) {
foreach my $add (0, ($mult==2 ? -1 : ())) {
foreach my $neg (0, 1) {
print "$mult*N+$add neg=$neg\n";
foreach my $tree_type (@$tree_type_aref) {
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
my $str = '';
# for (my $n = 1030; $n < 1080; $n += 1) {
for (my $n = 2; $n < 50; $n += 1) {
my ($x,$y) = $path->n_to_xy($n);
my $value = ($x ^ $y) & 1;
$value *= $mult;
$value += $add;
if ($neg) { $value = -$value; }
$str .= "$value,";
}
print "$tree_type $str\n";
system "grep -e '$str' ~/OEIS/stripped";
print "\n";
}
}
}
}
exit 0;
}
{
require Math::PlanePath::RationalsTree;
# SB 11xxxx and 0 or 2 mod 3
# CS 3,5 mod 6
# L 0,4 mod 6
# groups 1,1,3,5,11,21,43,85,171,341,683,1365,2731
# A001045 Jacobsthal a(n-1)+2*a(n-2)
# 3*a(n)+(-1)^n = 2^n
# Inverse: floor(log_2(a(n))=n-2 for n>=2
# D. E. Knuth, Art of Computer Programming, Vol. 3, Sect.
# 5.3.1, Eq. 13. On GCD
# Arises in study of sorting by merge insertions and in
# analysis of a method for computing GCDs - see Knuth
# reference.
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $tree_type (@$tree_type_aref) {
print "$tree_type\n";
my $path = Math::PlanePath::RationalsTree->new (tree_type => $tree_type);
my $count = 0;
my $group = 0;
my $prev_high_bit = 0b10;
foreach my $n ($path->n_start .. 50000) {
my ($x,$y) = $path->n_to_xy($n);
next unless $x>$y && ($x%2)!=($y%2); # P>Q not both odd
if (high_bit($n) != $prev_high_bit) {
print "group $group\n";
$prev_high_bit = high_bit($n);
$group = 0;
}
$group++;
# printf "%7b, # %d\n", $n, sans_high_bit(sans_high_bit($n))%3;
last if $count++ > 9000;
}
print "\n";
}
exit 0;
}
{
# X,Y list by levels
require Math::PlanePath::RationalsTree;
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $tree_type (@$tree_type_aref) {
print "$tree_type\n";
my $path = Math::PlanePath::RationalsTree->new
(
# tree_type => 'HCS',
tree_type => $tree_type,
# tree_type => 'CW',
# tree_type => 'SB',
);
my $non_monotonic = '';
foreach my $level (0 .. 6) {
my $nstart = 2**$level;
my $nend = 2**($level+1)-1;
my $prev_x = 1;
my $prev_y = 0;
print "$nstart ";
foreach my $n ($nstart .. $nend) {
if ($n != $nstart) { print " "; }
my ($x,$y) = $path->n_to_xy($n);
next unless $x>$y && ($x%2)!=($y%2); # P>Q not both odd
print "$x/$y";
unless (frac_lt($prev_y,$prev_x, $y,$x)) {
$non_monotonic ||= "at $y/$x";
}
$prev_x = $x;
$prev_y = $y;
}
print "\n";
# print " non-monotonic $non_monotonic\n";
}
}
exit 0;
}
{
# turn list with levels, or parity with levels
require Math::NumSeq::PlanePathTurn;
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'SB');
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
for (my $n = $seq->i_start; $n <= 16384; $n+=1) {
# next if $n % 2;
if (is_pow2($n)) {
printf "\n%5d ", $n;
}
# my $turn = $seq->ith($n);
my ($x,$y) = $path->n_to_xy($n);
# my $turn = ($x ^ $y) & 1;
my $turn = ($x&1) + 2*($y&1);
# if ($n % 8 == 0) { print " "; }
print "$turn";
}
print "\n";
exit 0;
}
{
# HCS turn left,right
require Math::NumSeq::PlanePathTurn;
require Math::BaseCnv;
require Math::PlanePath::GrayCode;
my $path = Math::PlanePath::RationalsTree->new(tree_type => 'HCS');
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => 'Right');
foreach my $n ($path->n_start+1 .. 255) {
# if (($n & 3) == 1 || ($n & 3) == 2) {
# next;
# }
my $turn = $seq->ith($n); # -1); # int(($n-1)/2));
# print "$turn,"; next;
my $n2 = Math::BaseCnv::cnv($n,10,2);
if (is_pow2($n)) { print "\n"; }
my ($x,$y) = $path->n_to_xy($n);
my $parity = hcs_turn_right($n) ? 1 : 0;
my $diff = ($parity == $turn ? '' : ' ***');
printf "%2s %5s %2s,%-2s %d %s%s\n",
$n, $n2, $x,$y, $turn, $parity, $diff;
}
# X/(X+Y), (X+Y)/Y high to low both shear only so no change
# SB Right when floor((N+1)/2 is odd or power 2^k.
# Right at first and last of row, otherwise LRRL repeat.
sub Zsb_turn_right { # bad
my ($n) = @_;
$n += ($n&1);
return (($n & 2) == 1 || ($n & ($n-1)) == 0);
}
sub Ysb_turn_right { # good
my ($n) = @_;
if ($n == 3) { return 0; }
$n = ($n+1) >> 1;
return (($n & 1) || is_pow2($n));
}
# N is 1or2 mod 4, or N=1111or10000 is N or N+1 is pow2
sub sb_turn_right { # good
my ($n) = @_;
if ($n == 3) {
return 0;
}
if (($n & 3) == 1 || ($n & 3) == 2) {
return 1;
}
return is_pow2($n) || is_pow2($n+1);
}
sub XXsb_turn { # good
my ($n) = @_;
### sb_turn(): "$n binary ".sprintf('%b',$n)
my $bit = high_bit($n);
### high: "bit=".sprintf('%b',$bit)
$n -= $bit;
for ($bit >>= 1; $bit > 2; $bit >>= 1) {
### at: "n=".sprintf('%b',$n)." bit=".sprintf('%b',$bit)
if ($n & $bit) {
$n -= $bit;
$n ^= ($bit-1);
}
if ($n == $bit-1) {
return 0;
}
}
return 1;
}
sub hcs_turn_right { # good
my ($n) = @_;
return count_1_bits($n+1) & 1;
}
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
# Y/(X+Y) and (X+Y)/X high to low
# so transpose on every new bit inserted
sub bird_turn_right { # good
my ($n) = @_;
if ($n == 2) { return 1; }
$n++;
$n >>= 1;
if ($n == high_bit($n)) {
return 0; # first and last of row always 0
}
my $ret = bit_length($n) & 1; # rows alternately 1s and 0s
if (($n & 3) == 0) { # but 0mod8 and 7mod8 flip by low 0s
my $c = count_low_0_bits($n);
$ret ^= ($c & 1) ^ 1;
}
return $ret;
}
sub bit_length {
my ($n) = @_;
my $len = 0;
while ($n) {
$n >>= 1;
$len++;
}
return $len;
}
sub count_low_0_bits {
my ($n) = @_;
if ($n == 0) { return 0; }
my $count = 0;
until ($n % 2) {
$count++;
$n /= 2;
}
return $count;
}
# 0 1 2 3 4 5 6 7 8 9 A B C D E F
# 1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0
#
sub ayt_turn_right { # wrong
my ($n) = @_;
if (($n & 3) == 1 || ($n & 3) == 2) {
return 1;
}
my $bit = high_bit($n);
if (bit_length($n) & 1) {
return ($n == $bit+$bit/2 || $n == $bit+$bit/2-1 ? 1 : 0);
} else {
return ($n == $bit || $n == 2*$bit-1 ? 0 : 1);
}
}
sub drib_turn_right { # wrong
my ($n) = @_;
if (($n & 3) == 1 || ($n & 3) == 2) {
return 1;
}
my $bit = high_bit($n);
if (bit_length($n) & 1) {
return ($n == $bit+$bit/2 || $n == $bit+$bit/2-1 ? 1 : 0);
} else {
return ($n == $bit || $n == 2*$bit-1 ? 0 : 1);
}
}
# C 3,5 R
# A 1,4 P->A X/X+Y shear North
# P 1,3 B 4,3 L P->B X+Y/Y shear East
# Q 3,2 D 5,2 Q->C X/X+Y shear North
# Q->D X+Y/Y shear East
# X=1 X=3 X=4 X=5
sub cw_turn_right { # wrong
my ($n) = @_;
my $bit = high_bit($n);
$n -= $bit;
while ($bit > 2) {
if ($n & $bit) {
$n -= $bit;
$n ^= ($bit-1);
}
if ($n == 1 || $n == 2) {
return 0;
}
$bit >>= 1;
}
return 1;
return 0;
}
sub to_gray {
my ($n) = @_;
my $digits = [ digit_split_lowtohigh($n,2) ];
Math::PlanePath::GrayCode::_digits_to_gray_reflected($digits,2);
return digit_join_lowtohigh($digits,2);
}
sub from_gray {
my ($n) = @_;
my $digits = [ digit_split_lowtohigh($n,2) ];
Math::PlanePath::GrayCode::_digits_from_gray_reflected($digits,2);
return digit_join_lowtohigh($digits,2);
}
sub sans_high_bit {
my ($n) = @_;
return $n ^ high_bit($n);
}
sub high_bit {
my ($n) = @_;
my $bit = 1;
while ($bit <= $n) {
$bit <<= 1;
}
return $bit >> 1;
}
exit 0;
}
{
# HCS vs Bird
require Math::NumSeq::PlanePathTurn;
my $hcs = Math::PlanePath::RationalsTree->new(tree_type => 'HCS');
my $bird = Math::PlanePath::RationalsTree->new(tree_type => 'Bird');
my $n = 0b1000000010000000000;
my ($x,$y) = $hcs->n_to_xy($n);
my $nb = $bird->xy_to_n($x,$y);
printf "%10b\n", $n;
printf "%10b\n", $nb;
exit 0;
}
{
# Minkowski question mark
#
# cf = [0,a1,a2,...] range 0to1
# (-1)^(k-1)
# ? = sum -----------
# k 2^(a1+...+ak-1)
# (-1)^(1-1)/2^a1 = 1/2^a1 = 0.000..001 binary
# + (-1)^(1-2)/2^(a1+a2) = -1/2^(a1+a2)
# = 0.0001 - 0.000000001
# = 0.000011111
#
# 0to1 cf = [0,a0,a1,...]
# ? = 2*(1 - 2^-a0 + 2^-(a0+a1) - 2^-(a0+a1+a2) + ...)
#
# ? =
#
# ?(1/k^n) = 1/2^(k^n-1)
# ?(0) = 0
# ?(1/3) = 1/4
require Math::BaseCnv;
require Math::BigRat;
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
# ?(1/3)=1/4 ?(1/2)=1/2 ?(2/3)=3/4
foreach my $xy ('1/3', '1/2', '2/3') {
my ($x,$y) = split m{/}, $xy;
try ($x,$y);
}
foreach my $n ($path->n_start .. 64) {
my ($x,$y) = $path->n_to_xy($n);
try ($x,$y);
}
foreach my $xy ('1/3', '1/2', '2/3') {
my ($x,$y) = split m{/}, $xy;
try ($x,$y);
}
sub try {
my ($x,$y) = @_;
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $cfrac_str = $cfrac->to_ascii;
my $n = $path->xy_to_n($x,$y);
my $nbits = Math::BaseCnv::cnv($n,10,2);
my $mp = minkowski_by_path($x,$y);
my $mc = minkowski_by_cfrac($x,$y);
my $mpstr = to_binary($mp);
my $mcstr = to_binary($mc);
print "$x/$y $nbits p=$mp c=$mc $cfrac_str\n";
}
# pow=2^level <= N
# ? = (2*(N-pow) + 1) / pow
# = (2N - 2pow + 1) / pow
# = (2N+1)/pow - 2pow/pow
# = (2N+1)/pow - 2
# = 2*((N+1/2)/pow - 1)
sub minkowski_by_path {
my ($x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
my ($pow,$exp) = round_down_pow($n,2);
return Math::BigRat->new(2*$n+1) / $pow - 2;
return Math::BigRat->new(2*($n-$pow) + 1) / $pow;
return (2*($n-$pow) + 1) / $pow;
return (2*$pow-1 - $n) / $pow;
return $n / (2*$pow);
}
# q0, q1, ...
# 1 1 1
# ? = 2 * (1 - --- * (1 - ---- * (1 - ---- * (...
# 2^q0 2^q1 2^q2
#
sub minkowski_by_cfrac {
my ($x,$y) = @_;
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $aref = $cfrac->to_array; # first to last
### $aref
my $ret = 1;
foreach my $q (reverse @$aref) {
$ret = 1 - 1/Math::BigRat->new(2)**$q * $ret;
}
return 2*$ret;
}
# q0, q1, ...
# (-1)^k
# ? = sum -------------------
# k 2^(q0+q1+...qk - 1)
sub minkowski_by_cfrac_cumul {
my ($x,$y) = @_;
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $aref = $cfrac->to_array;
### $aref
my $ret = 1;
my $sign = Math::BigRat->new(1);
my $pos = 0;
foreach my $q (@$aref) {
$sign = -$sign;
$pos += $q;
$ret += $sign / (Math::BigInt->new(2) ** $pos);
}
return 2*$ret;
}
# pow=2^level <= N
# F = (2*(N-pow) + 1) / pow / 2
# = ((N-pow) + 1/2) / pow
sub F_by_path {
my ($x,$y) = @_;
my $n = $path->xy_to_n($x,$y);
my ($pow,$exp) = round_down_pow($n,2);
return Math::BigRat->new(2*$n+1) / $pow - 2;
return Math::BigRat->new(2*($n-$pow) + 1) / $pow;
}
# q0, q1, ...
#
# (-1)^k
# F = sum -------------------
# k 2^(q0+q1+...qk)
sub F_by_cfrac {
my ($x,$y) = @_;
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $aref = $cfrac->to_array;
### $aref
my $ret = 1;
my $sign = Math::BigRat->new(1);
my $pos = 0;
foreach my $q (@$aref) {
$sign = -$sign;
$pos += $q;
$ret += $sign / (Math::BigInt->new(2) ** $pos);
}
return $ret;
}
sub to_binary {
my ($n) = @_;
my $str = sprintf '%b', int($n);
$n -= int($n);
if ($n) {
$str .= '.';
while ($n) {
$n *= 2;
if ($n >= 1) {
$n -= 1;
$str .= '1';
} else {
$str .= '0';
}
}
}
return $str;
}
exit 0;
}
{
# A108356 partial sums
# A108357 AYT 2N left or 2N+1 right within a row but not across it
# (1+x^2+x^4)/(1-x^8) repeat of 10101000
# 8 7 6 5 4 3 2 1 0-1-2-3-4-5
# 0,0,0,0,1,0,1,0,1,0,0,0,0,0
# -1 0 0 0 0 0 0 0 1 -1
require Math::Polynomial;
Math::Polynomial->string_config({ ascending => 1 });
my $num = Math::Polynomial->new(1,0,1,0,1);
my $den = Math::Polynomial->new(1,0,0,0,0,0,0,0,-1);
{
my %seen;
my $when = 1;
for (;;) {
$num <<= 1;
my $q = $num / $den;
$num %= $den;
print "$q $num\n";
if (my $prev = $seen{$num}) {
print "at $when repeat of $prev\n";
last;
}
$seen{$num} = $when++;
}
exit 0;
}
{
$num <<= 270;
$num /= $den;
$num = -$num;
print $num,"\n";
while ($num) {
print $num->coeff(0);
$num >>= 1;
}
print "\n";
exit 0;
# 1010001010100010101000101010001010100010101000101010001010100010101
# 101010001010100010101000101010001010100010101000101010001010100010101000
}
}
{
# turn search
require Math::NumSeq::PlanePathTurn;
my $tree_type_aref = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
foreach my $mult (1,2) {
foreach my $add (0, ($mult==2 ? 1 : ())) {
foreach my $turn_type ('Left','Right','LSR') {
foreach my $neg (0, ($turn_type eq 'LSR' ? 1 : ())) {
print "$mult*N+$add $turn_type neg=$neg\n";
foreach my $tree_type (@$tree_type_aref) {
my $path = Math::PlanePath::RationalsTree->new(tree_type => $tree_type);
my $seq = Math::NumSeq::PlanePathTurn->new (planepath_object => $path,
turn_type => $turn_type);
my $str = '';
# foreach my $n (1030 .. 1080) {
foreach my $n (2 .. 50) {
my $value = $seq->ith($mult*$n+$add);
if ($neg) { $value = -$value; }
$str .= "$value,";
}
print "$tree_type $str\n";
system "grep -e '$str' ~/OEIS/stripped";
print "\n";
}
}
}
}
}
exit 0;
}
{
# count 0-bits below high 1
# 1 2 3 4 5 6 7 8
# 0,1,0,2,1,0,0,3,2,1,1,0,0,0,0,4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0,5,
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# SB int(x/y) 1,0,2,0,0,1,3,0,0,0, 0, 1, 1, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1
# count
# count high 1-bits, is +1 except at n=2^k
# 0,1,1,2,1,1,2,3,1,1,1, 1, 2, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 2,
foreach my $n (1 .. 32) {
my $k = $n;
while (! is_pow2($k)) {
$k >>= 1;
}
my ($pow,$exp) = round_down_pow($k,2);
print "$exp,";
}
print "\n";
exit 0;
sub is_pow2 {
my ($n) = @_;
while ($n > 1) {
if ($n & 1) {
return 0;
}
$n >>= 1;
}
return ($n == 1);
}
}
{
# X,Y list cf pythag odd,even
require Math::PlanePath::RationalsTree;
foreach my $path
(Math::PlanePath::RationalsTree->new(tree_type => 'SB'),
Math::PlanePath::RationalsTree->new(tree_type => 'CW'),
Math::PlanePath::RationalsTree->new(tree_type => 'HCS'),
Math::PlanePath::RationalsTree->new(tree_type => 'AYT'),
Math::PlanePath::RationalsTree->new(tree_type => 'Drib'),
Math::PlanePath::RationalsTree->new(tree_type => 'Bird')) {
print "tree_type $path->{'tree_type'}\n";
foreach my $depth (0 .. 5) {
foreach my $n ($path->tree_depth_to_n($depth) ..
$path->tree_depth_to_n_end($depth)) {
my ($x,$y) = $path->n_to_xy($n);
my $flag = '';
if ($x%2 != $y%2) {
$flag = ($x%2?'odd':'even').','.($y%2?'odd':'even');
}
my $octant = '';
if ($y < $x) {
$octant = 'octant';
}
printf "N=%2d %2d / %2d %10s %10s\n", $n, $x,$y, $flag, $octant;
$n++;
}
print "\n";
}
}
exit 0;
}
{
# HCS runs
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'HCS');
my ($x,$y) = $path->n_to_xy(0b10000001001001000);
# \-----/\-/\-/\--/
# 7 3 3 4
# is [6, 3, 3, 5]
($x,$y) = $path->n_to_xy(0b11000001);
# |\----/|
# 1 6 1
# is [0, 6, 2]
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $cfrac_str = $cfrac->to_ascii;
say $cfrac_str;
exit 0;
}
{
# A072726 numerator of rationals >= 1 with continued fractions even terms
# A072727 denominator
# A072728 numerator of rationals >= 1 with continued fraction terms 1,2 only
# A072729 denominator
require Math::NumSeq::OEIS;
require Math::PlanePath::RationalsTree;
my $num = Math::NumSeq::OEIS->new (anum => 'A072726');
my $den = Math::NumSeq::OEIS->new (anum => 'A072727');
my $tree_types = Math::PlanePath::RationalsTree->parameter_info_hash->{'tree_type'}->{'choices'};
my @paths = map { Math::PlanePath::RationalsTree->new (tree_type => $_) }
@$tree_types;
print " ",join(' ',@$tree_types),"\n";
foreach (1 .. 120) {
(undef, my $x) = $num->next;
(undef, my $y) = $den->next;
print "$x/$y";
foreach my $path (@paths) {
print " ";
my $n = $path->xy_to_n($x,$y);
if (! defined $n) {
print "undef";
next;
}
printf '%b', $n;
}
print "\n";
}
exit 0;
}
{
# L-tree OFFSET=0 for 0/1
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
# A174981(n) num 0, 1, 1, 2, 3, 1, 2, 3, 5, 2, 5, 3, 4, 1, 3,
# A002487(n+2) den 1, 2, 1, 3, 2, 3, 1, 4, 3, 5, 2, 5, 3, 4, 1,
# A174980 den, stern variant
my $path = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
foreach my $n (0 .. 15) {
my ($x,$y) = $path->n_to_xy($n);
$x //= 'undef';
$y //= 'undef';
my $ln = cw_to_l($n);
print "$n $x,$y $ln\n";
}
sub cw_to_l {
my ($n) = @_;
$n++;
my ($pow,$exp) = round_down_pow($n,2);
$n ^= $pow-1;
# $n--;
# $n |= $pow;
return $n-1;
}
exit 0;
}
{
# permutations in N row
my $choices = Math::PlanePath::RationalsTree->parameter_info_hash
->{'tree_type'}->{'choices'};
my %seen;
foreach my $from_type (@$choices) {
my $from_path = Math::PlanePath::RationalsTree->new (tree_type => $from_type);
foreach my $to_type (@$choices) {
next if $from_type eq $to_type;
my $to_path = Math::PlanePath::RationalsTree->new (tree_type => $to_type);
{
my $str = '';
foreach my $from_n (2 .. 25) {
my ($x,$y) = $from_path->n_to_xy($from_n);
my $to_n = $to_path->xy_to_n($x,$y);
$str .= "$to_n,";
}
next if $seen{$str}++;
print "$from_type->$to_type http://oeis.org/search?q=$str\n";
}
{
my $str = '';
foreach my $from_n (2 .. 25) {
my ($x,$y) = $from_path->n_to_xy($from_n);
my $to_n = $to_path->xy_to_n($x,$y);
$to_n ^= $from_n;
# $str .= "$to_n,";
$str .= sprintf '%d,', $to_n;
}
next if $seen{$str}++;
print "$from_type->$to_type XOR http://oeis.org/search?q=$str\n";
}
}
print "\n";
}
exit 0;
}
{
# 49/22
# ### nbits apply CW: [
# ### '0',
# ### '1',
# ### '1',
# ### '0',
# ### '0',
# ### '0',
# ### '0',
# ### '1',
# ### '1'
# ### ]
# HCS
# 49/22
# 27/22 X
# 5/22 X
# 5/17 Y
# 5/12 Y
# 5/7 Y
# 5/2 Y
# 3/2 X
# 1/2 X
# 1/1 Y
# 1 . = 1
# 10 .0. = 2
# 100 .0.0. = 3
# 1000 .0.0.0. = 4
# 1 00 1000 10 1
# \/ \--/ \/ ^
# 2 4 2 2
# 0,
# 1, . 1
#
# 1/2 .0. = .. = 2 -> 2 = 1/2
# 2 .1. = 1,1 -> 0,2 = 0 + 1/(0+1/2) = 2
#
# 3/2 .0.0. = ... = 3 = 0 + 1/3
# 1/3 .0.1. = ..1. = 2,1 -> 1,2 = 0+1/(1+1/2) = 2/3
# 2/3 .1.0. = .1.. = 1,2 -> 0,3 = 0+1/(0+1/3) = 3
# 3 .1.1. = 1,1,1 -> 0,1,2 = 0+1/(0+1/(1+1/2)) = 3/2
#
# 100 .. 111 SB 1/3 2/3 3/2 3/1
# 5/2 4/3 5/3 1/4 2/5 3/4 3/5 4 1000 .. 1111 SB 1/4 .. 4/1
# CW: 224 11100000 3/16 [0, 5, 3]
# HCS: 194 3.0000, 16.0000 194 1_4096 0.000,1.000(1.0000) c=388,389
# 194 = binary 11000010
# 0 5 3
# 1.1.0.0.0.0.1.0. = .1.....1.. = 1,5,2 -> 0,5,3 = 0+1/(5+1/3) = 3/16
#
# AYT
# 836 49.0000, 22.0000 836 1_268435456
# 1001000101 = 581
# 1101000100 = 836
# |\/\--/\/
# 22 4 2
my $x = 1;
my $y = 1;
foreach my $nbit (0,0, 1,0,0,0, 1,0, 1) {
$y += $x;
if (! $nbit) {
($x,$y) = ($y,$x);
}
}
# foreach my $nbit (reverse 0,0, 1,0,0,0, 1,0, 1) {
# # foreach my $nbit (reverse 0,0,0,0) {
# $x += $y;
# if ($nbit) {
# ($x,$y) = ($y,$x);
# }
# }
print "$x,$y\n";
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $cfrac_str = $cfrac->to_ascii;
print "$cfrac_str\n";
exit 0;
}
{
# AYT vs continued fraction
require Math::ContinuedFraction;
require Math::BaseCnv;
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my $level = 10;
foreach my $n (1 .. 2**$level) {
my ($x,$y) = $ayt->n_to_xy($n);
my $cfrac = Math::ContinuedFraction->from_ratio($x,$y);
my $cfrac_str = $cfrac->to_ascii;
my $nbits = Math::BaseCnv::cnv($n,10,2);
printf "%3d %7s %2d/%-2d %s\n", $n, $nbits, $x,$y, $cfrac_str;
}
exit 0;
}
{
require Math::ContinuedFraction;
my $cfrac = Math::ContinuedFraction->from_ratio(29,42);
my $cfrac_str = $cfrac->to_ascii;
print "$cfrac_str\n";
exit 0;
}
{
# lengths of frac or bits
require Math::PlanePath::DiagonalRationals;
require Math::PlanePath::CoprimeColumns;
require Math::PlanePath::PythagoreanTree;
foreach my $path (Math::PlanePath::DiagonalRationals->new,
Math::PlanePath::CoprimeColumns->new,
Math::PlanePath::PythagoreanTree->new(coordinates=>'PQ'),
) {
print join(',', map{cfrac_length($path->n_to_xy($_))} 2 .. 32),"\n";
print join(',', map{bits_length ($path->n_to_xy($_))} 2 .. 32),"\n";
print "\n";
}
exit 0;
sub bits_length {
my ($x,$y) = @_;
return sum(0, Math::PlanePath::RationalsTree::_xy_to_quotients($x,$y));
}
sub cfrac_length {
my ($x,$y) = @_;
my @quotients = Math::PlanePath::RationalsTree::_xy_to_quotients($x,$y);
return scalar(@quotients);
}
}
{
# 167/3
require Math::BigInt;
my $path = Math::PlanePath::RationalsTree->new;
my $x = Math::BigInt->new(167);
my $y = Math::BigInt->new(3);
my $n = $path->xy_to_n($x,$y);
print $n,"\n";
my $binstr = $n->as_bin;
$binstr =~ s/0b//;
print $binstr,"\n";
print length($binstr),"\n";
exit 0;
}
{
my $cw = Math::PlanePath::RationalsTree->new(tree_type => 'CW');
my $ayt = Math::PlanePath::RationalsTree->new (tree_type => 'AYT');
my $level = 6;
foreach my $cn (2**$level .. 2**($level+1)-1) {
my ($cx,$cy) = $cw->n_to_xy($cn);
my $an = $ayt->xy_to_n($cx,$cy);
my ($z,$c) = cw_to_ayt($cn);
my ($t,$u) = ayt_to_cw($an);
printf "%5s %b %b %b(%b)%s %b(%b)%s\n",
"$cx/$cy", $cn, $an,
$z, $c, ($z == $an ? " eq" : ""),
$t, $u, ($t == $cn ? " eq" : "");
}
exit 0;
sub cw_to_ayt {
my ($c) = @_;
my $z = 0;
my $flip = 0;
for (my $bit = 1; $bit <= (1 << ($level-1)); $bit <<= 1) { # low to high
if ($flip) { $c ^= $bit; }
if ($c & $bit) {
} else {
$z |= $bit;
$flip ^= 1;
}
}
$z += (1 << $level);
$c &= (1 << $level) - 1;
return $z,0;
}
sub ayt_to_cw {
my ($a) = @_;
$a &= (1 << $level) - 1;
my $t = 0;
my $flip = 0;
for (my $bit = (1 << ($level-1)); $bit > 0; $bit >>= 1) { # high to low
if ($a & $bit) {
$a ^= $bit;
$t |= $bit;
$flip ^= 1;
} else {
}
if ($flip) { $t ^= $bit; }
}
if (!$flip) { $t = ~$t; }
$t &= (1 << $level) - 1; # mask to level
$t += (1 << $level); # high 1-bit
return ($t,$a);
}
}
{
require Math::ContinuedFraction;
{
my $cf = Math::ContinuedFraction->new([0,10,2,1,8]);
print $cf->to_ascii,"\n";
print $cf->brconvergent(4),"\n";
}
{
my $cf = Math::ContinuedFraction->from_ratio(26,269);
print $cf->to_ascii,"\n";
}
exit 0;
}
{
my $n = 12590;
my $radix = 3;
while ($n) {
my $digit = $n % $radix;
if ($digit == 0) {
$digit = $radix;
}
$n -= $digit;
($n % $radix) == 0 or die;
$n /= $radix;
print "$digit";
}
print "\n";
exit 0;
}
{
my $n = 12590;
my $radix = 3;
my @digits = digit_split_lowtohigh($n,$radix);
my $borrow = 0;
foreach my $i (0 .. $#digits) {
$digits[$i] -= $borrow;
if ($digits[$i] <= 0) {
$digits[$i] += $radix;
$borrow = 1;
} else {
$borrow = 0;
}
}
$borrow == 0 or die;
print reverse(@digits),"\n";
exit 0;
}
{
my $n = 0;
my @digits = (1,2,1,3,1,3,3,2,2);
my $power = 1;
foreach my $digit (@digits) {
$power *= 3;
$n += $power * $digit;
}
print $n;
exit 0;
}
{
require Math::ContinuedFraction;
my $sb = Math::PlanePath::RationalsTree->new(tree_type => 'SB');
for (my $n = $sb->n_start; $n < 3000; $n++) {
my ($x,$y) = $sb->n_to_xy ($n);
next if $x > $y;
my $cf = Math::ContinuedFraction->from_ratio($x,$y);
my $cfstr = $cf->to_ascii;
my $cfaref = $cf->to_array;
my $cflen = scalar(@$cfaref);
my $nhex = sprintf '0x%X', $n;
print "$nhex $n $x/$y $cflen $cfstr\n";
}
exit 0;
}
{
my $sb = Math::PlanePath::RationalsTree->new (tree_type => 'SB');
my $bird = Math::PlanePath::RationalsTree->new(tree_type => 'Bird');
my $level = 5;
foreach my $an (2**$level .. 2**($level+1)-1) {
my ($ax,$ay) = $sb->n_to_xy($an);
my $bn = $bird->xy_to_n($ax,$ay);
my ($z,$c) = sb_to_bird($an);
my ($t,$u) = bird_to_sb($bn);
printf "%5s %b %b %b(%b)%s %b(%b)%s\n",
"$ax/$ay", $an, $bn,
$z, $c, ($z == $bn ? " eq" : ""),
$t, $u, ($t == $an ? " eq" : "");
}
exit 0;
sub sb_to_bird {
my ($n) = @_;
for (my $bit = (1 << ($level-1)); $bit > 0; $bit >>= 1) { # high to low
$bit >>= 1;
$n ^= $bit;
}
return $n,0;
}
sub bird_to_sb {
my ($n) = @_;
for (my $bit = (1 << ($level-1)); $bit > 0; $bit >>= 1) { # high to low
$bit >>= 1;
$n ^= $bit;
}
return $n,0;
}
sub ayt_to_bird {
my ($a) = @_;
### bird_to_ayt(): sprintf "%b", $a
my $z = 0;
my $flip = 1;
$a = _reverse($a);
for (my $bit = 1; $bit <= (1 << ($level-1)); $bit <<= 1) { # low to high
### a bit: ($a & $bit)
### $flip
if ($a & $bit) {
if (! $flip) {
$z |= $bit;
}
} else {
$flip ^= 1;
if ($flip) {
$z |= $bit;
}
}
### z now: sprintf "%b", $z
### flip now: $flip
}
$z += (1 << $level);
$a &= (1 << $level) - 1;
return $z,0;
}
sub bird_to_ayt {
my ($b) = @_;
$b = _reverse($b);
$b &= (1 << $level) - 1;
my $t = 0;
my $flip = 1;
for (my $bit = (1 << ($level-1)); $bit > 0; $bit >>= 1) { # high to low
if ($b & $bit) {
if ($flip) {
$t |= $bit;
}
$flip ^= 1;
} else {
if (! $flip) {
$t |= $bit;
}
}
# if ($flip) { $t ^= $bit; }
}
if (!$flip) { $t = ~$t; }
$t &= (1 << $level) - 1;
$t += (1 << $level);
return ($t,0); # $b);
}
sub _reverse {
my ($n) = @_;
my $rev = 1;
while ($n > 1) {
$rev = 2*$rev + ($n % 2);
$n = int($n/2);
}
return $rev;
}
}
{
# diatomic 0,1,1,2,1,3,2,3, 1,4,3,5,2,5,3,4, 1,5,4,7,3,8,5,7,2,7,5,8,3,7,4,5,1,6,5,9,4,11,7,10,3,11,8,13,5,12,7,9,2,9,7,12,5,13,8,11,3,10,7,11,4,9,5,6,1,7,6,11,5,14,9,13,4,15,11,18,7,17,
my $ayt = Math::PlanePath::RationalsTree->new(tree_type => 'AYT');
foreach my $level (0 .. 3) {
foreach my $n (2**$level .. 2**($level+1)-1) {
my ($x,$y) = $ayt->n_to_xy($n);
print "$x,";
}
}
print "\n";
my $prev_y = 1;
foreach my $level (0 .. 5) {
foreach my $n (reverse 2**$level .. 2**($level+1)-1) {
my ($x,$y) = $ayt->n_to_xy($n);
print "$n $x $y\n";
if ($x != $prev_y) {
print "diff\n";
}
$prev_y = $y;
}
}
exit 0;
}
{
require Math::PlanePath::RationalsTree;
my $path = Math::PlanePath::RationalsTree->new;
$, = ' ';
say $path->xy_to_n (9,8);
say $path->xy_to_n (2,3);
say $path->rect_to_n_range (9,8, 2,3);
exit 0;
}
{
require Math::PlanePath::RationalsTree;
my $path = Math::PlanePath::RationalsTree->new;
require Math::BigInt;
# my ($n_lo,$n_hi) = $path->xy_to_n (1000,0, 1500,200);
my $n = $path->xy_to_n (Math::BigInt->new(1000),1);
### $n
### n: "$n"
require Math::NumSeq::All;
my $seq = Math::NumSeq::All->new;
my $pred = $seq->pred($n);
### $pred
exit 0;
}
{
require Math::PlanePath::RationalsTree;
my $cw = Math::PlanePath::RationalsTree->new (tree_type => 'CW');
my $drib = Math::PlanePath::RationalsTree->new(tree_type => 'Drib');
my $level = 5;
foreach my $an (2**$level .. 2**($level+1)-1) {
my ($ax,$ay) = $cw->n_to_xy($an);
my $bn = $drib->xy_to_n($ax,$ay);
my ($z,$c) = cw_to_drib($an);
my ($t,$u) = drib_to_cw($bn);
printf "%5s %b %b %b(%b)%s %b(%b)%s\n",
"$ax/$ay", $an, $bn,
$z, $c, ($z == $bn ? " eq" : ""),
$t, $u, ($t == $an ? " eq" : "");
}
exit 0;
sub cw_to_drib {
my ($n) = @_;
for (my $bit = 2; $bit <= (1 << ($level-1)); $bit <<= 2) { # low to high
$n ^= $bit;
}
return $n,0;
}
sub drib_to_cw {
my ($n) = @_;
for (my $bit = 2; $bit <= (1 << ($level-1)); $bit <<= 2) { # low to high
$n ^= $bit;
}
return $n,0;
}
}
{
require Math::PlanePath::RationalsTree;
my $path = Math::PlanePath::RationalsTree->new
(
tree_type => 'AYT',
tree_type => 'CW',
tree_type => 'SB',
);
foreach my $y (reverse 1 .. 10) {
foreach my $x (1 .. 10) {
my $n = $path->xy_to_n($x,$y);
if (! defined $n) { $n = '' }
printf (" %4s", $n);
}
print "\n";
}
exit 0;
}
{
require Math::PlanePath::RationalsTree;
my $path = Math::PlanePath::RationalsTree->new
(
tree_type => 'AYT',
tree_type => 'CW',
tree_type => 'SB',
);
foreach my $y (2 .. 10) {
my $prev = 0;
foreach my $x (1 .. 100) {
my $n = $path->xy_to_n($x,$y) || next;
if ($n < $prev) {
print "not monotonic at X=$x,Y=$y n=$n prev=$prev\n";
}
$prev = $n;
}
}
exit 0;
}
sub frac_lt {
my ($p1,$q1, $p2,$q2) = @_;
return ($p1*$q2 < $p2*$q1);
}
Math-PlanePath-113/devel/hilbert-diamond.pl 0000644 0001750 0001750 00000003127 12023454743 016404 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use Image::Base::PNGwriter;
use Math::PlanePath::HilbertCurve;
#use Smart::Comments;
my $width = 500;
my $height = 500;
my $image = Image::Base::PNGwriter->new (-width => $width,
-height => $height);
my $scale = 20;
sub rotate {
my ($x, $y) = @_;
return ($scale * ($x + $y) + $scale, $scale * ($x - $y) + int($height/2));
}
my $path = Math::PlanePath::HilbertCurve->new;
my ($prev_x, $prev_y) = $path->n_to_xy(0);
my ($prev_rx, $prev_ry) = rotate($prev_x, $prev_y);
foreach my $n (1 .. 64) {
my ($x, $y) = $path->n_to_xy($n);
### xy: "$x,$y"
my ($rx, $ry) = rotate($x,$y);
$image->line ($rx,$ry, $prev_rx,$prev_ry, 'white');
### line: "$rx,$ry, $prev_rx,$prev_ry"
($prev_x, $prev_y) = ($x, $y);
($prev_rx, $prev_ry) = ($rx, $ry);
}
$image->save ('/tmp/x.png');
system ('xzgv /tmp/x.png');
exit 0;
Math-PlanePath-113/devel/cellular-rule62.pl 0000644 0001750 0001750 00000003143 11646221732 016260 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use strict;
my $rule = 57;
my @table = map {($rule & (1<<$_)) ? 1 : 0} 0 .. 7;
print join(',',@table),"\n";
my @mirror = (map { ($_&4?1:0)+($_&2?2:0)+($_&1?4:0) } 0 .. 7);
print "join table ",oct('0b'. join('', map{$table[$_]} reverse 0 .. 7)),"\n";
print "join table ",oct('0b'. join('', map{$table[$mirror[$_]]} reverse 0 .. 7)),"\n";
# uncomment this to run the ### lines
#use Devel::Comments;
my @a = ([(0)x50, 1, (0)x50]);
print_line(0);
foreach my $level (1..20) {
my $prev = $a[$level-1];
### @a
foreach my $i (1 .. $#$prev) {
my $p = 4*($prev->[$i-1]||0) + 2*($prev->[$i]||0) + ($prev->[$i+1]||0);
$a[$level]->[$i] = $table[$p];
}
print_line($level);
}
sub print_line {
my ($level) = @_;
foreach my $i (0 .. $#{$a[$level]}) {
my $c = $a[$level]->[$i];
if ($table[0]) {
print $c ? ' ' : "*";
} else {
print $c ? '*' : " ";
}
}
print "\n";
}
exit 0;
Math-PlanePath-113/devel/l-tiling.pl 0000644 0001750 0001750 00000005323 12142113042 015043 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use strict;
use Math::PlanePath::LTiling;
# LTiling A112539 Half-baked Thue-Morse: at successive steps the sequence or its bit-inverted form is appended to itself.
{
# A139351 count 1-bits at even positions
# A139352 count 1-bits at odd positions
# A112539 1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,1,0,1,0, OFFSET=1
# A139351 0,1,0,1,1,2,1,2,0,1,0,1,1,2,1,2,1,2,1,2,2,3,2,3, OFFSET=0
# A139352 0,0,1,1,0,0,1,1,1,1,2,2,1,1,2,2,0,0,1,1,0,0,1,1, OFFSET=0
sub count_even_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 2;
}
return $count;
}
foreach my $n (2 .. 30) {
print count_even_1_bits($n),",";
}
print "\n";
exit 0;
}
{
# X,Y parity
# block 0, 2 unchanged 00 10
# block 1, 3 flip 01 11
# so flip by every second bit starting from lowest
#
# "middle" invert each
# "ends" duplicate each
# "all" 011 base then floor(n/3) inversions
my $path = Math::PlanePath::LTiling->new;
foreach my $n ($path->n_start .. 70) {
my ($x,$y) = $path->n_to_xy($n);
print(($x+$y)%2);
}
print "\n";
$path = Math::PlanePath::LTiling->new (L_fill => 'left');
foreach my $n ($path->n_start .. 70) {
my ($x,$y) = $path->n_to_xy($n);
print(($x+$y)%2);
}
print "\n";
$path = Math::PlanePath::LTiling->new (L_fill => 'upper');
foreach my $n ($path->n_start .. 70) {
my ($x,$y) = $path->n_to_xy($n);
print(($x+$y)%2);
}
print "\n";
$path = Math::PlanePath::LTiling->new (L_fill => 'ends');
for (my $n = $path->n_start+0; $n < 70; $n+=2) {
my ($x,$y) = $path->n_to_xy($n);
print(($x+$y)%2);
}
print "\n";
exit 0;
}
#
# +-------+
# | |
# | |
# | |
# | +---+
# | | |
# | | +-+
# | | | |
# +---+-| +-+-+---+
# | | | | | |
# | +-| +---+ | |
# | | | | | |
# +-| +---+---+ |
# | | | | |
# | +---+ | |
# | | | |
# +---+---+-------+
#
#
#
Math-PlanePath-113/devel/dragon.logo 0000644 0001750 0001750 00000003625 12041163010 015124 0 ustar gg gg #!/usr/bin/ucblogo
; Copyright 2012 Kevin Ryde
;
; This file is part of Math-PlanePath.
;
; Math-PlanePath 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, or (at your option) any later
; version.
;
; Math-PlanePath 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 Math-PlanePath. If not, see .
; http://rosettacode.org/wiki/Dragon_curve
;------------------------------------------------------------------------------
; ;;------------------------------------------------------------------------------
;
; or parameter for left/right side and negative angle for backward arc
to arc.turn :angle :radius
localmake "rightangle ifelse :angle>0 [90] [-90]
right :rightangle
penup
forward :radius
pendown
right 180 ; pointing towards original position
arc :angle :radius
right :angle ; pointing towards end of arc
penup
forward :radius
pendown
right :rightangle
end
to dragon.arcs :steps
localmake "step.radius 12
repeat :steps [
arc.turn (- dragon.turn.angle repcount) :step.radius
]
end
; dragon.arcs 512
; forward 100
; arc.turn 45 100
; wait 60
; wait 60
; clearscreen
; dragon.chamfer 256
; penup
; forward 10
; left dragon.turn.angle repcount
; forward 10
; pendown
; arc 90 10
; epspict "/tmp/x.eps
; ; do.while
; ; .setfirst
; ; .maybeoutput
; ; * + - /
; ; <
; ; <=
; ; <>
; ; =
; ; >
; ; >=
; ; `
; ; refresh
; ; .SETSEGMENTSIZE
; ; /so/logo/ucblogo-6.0/csls/
;
; ; to sgn :x
; ; output ifelse (:x > 0) [1] [-1]
; ; end
Math-PlanePath-113/devel/hexhypot.pl 0000644 0001750 0001750 00000003054 11566406004 015207 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Smart::Comments;
{
my $x = 2;
my $y = 0;
### initial: "$x,$y"
foreach (1 .. 6) {
# ($x,$y) = (($x+3*$y)/-2, # 120
# ($x-$y)/2);
# ($x,$y) = ((3*$y-$x)/2, # 2x120
# ($x+$y)/-2);
# ($x,$y) = (($x-3*$y)/2, # 60
# ($x+$y)/2);
($x,$y) = (($x+3*$y)/2, # -60
($y-$x)/2);
### to: "$x,$y"
}
exit 0;
}
{
my @seen;
foreach my $x (2 .. 20) {
my $ylimit = $x/3;
for (my $y = ($x&1); $y <= $ylimit; $y+=2) {
my $h = 3*$y*$y + $x*$x;
if ($seen[$h]) {
print "duplicate $x,$y: $seen[$h]\n";
} else {
$seen[$h] = "$x,$y";
}
}
}
my @hypots = map {defined $seen[$_] ? $_ : ()} 0 .. $#seen;
@hypots = sort {$a<=>$b} @hypots;
$,=',';
print @hypots,"\n";
exit 0;
}
Math-PlanePath-113/devel/gcd-rationals.pl 0000644 0001750 0001750 00000011074 12155444446 016076 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use Math::PlanePath::GcdRationals;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
use Smart::Comments;
{
require Math::PlanePath::PyramidRows;
my $path = Math::PlanePath::GcdRationals->new;
my $rows = Math::PlanePath::PyramidRows->new (step => 1);
require Math::NumSeq::OEIS;
my $A167192 = Math::NumSeq::OEIS->new (anum => 'A167192');
my $A002260 = Math::NumSeq::OEIS->new (anum => 'A002260');
my $A002024 = Math::NumSeq::OEIS->new (anum => 'A002024');
foreach my $n (1 .. 40) {
my ($x,$y) = $path->n_to_xy($n);
# my ($i,$j) = $rows->n_to_xy($n);
# $i++, $j++;
my $i = $A002260->ith($n);
my $j = $A002024->ith($n);
my $g = Math::PlanePath::GcdRationals::_gcd($i,$j);
my $jy = $j/$g;
# my $ix = $j + ($i-$j)/$g;
# my $ix = $j - $A167192->ith($n);
my $ix = $A002024->ith($n) - $A167192->ith($n);
my $diff = ($ix==$x && $jy==$y ? '' : ' ***');
print "$n $i,$j $x,$y $ix,$jy$diff\n";
# print "$x/$y, ";
# print(($j-$i)/$g,",");
}
exit 0;
# X = (i + j*(gcd-1)) / gcd
# = (i + j*gcd-j) / gcd
# = j + (i -j) / gcd
}
{
# nhi roughly max(num,den)**2
my $path = Math::PlanePath::GcdRationals->new (pairs_order => "diagonals_down");
foreach my $n (1 .. 5000) {
my ($x,$y) = $path->n_to_xy($n);
# my $nhi = 2 * max($x,$y)**2;
my $nhi = max($x,$y)**2;
my $flag = ($nhi < $n ? '****' : '');
print "$n $nhi$flag\n";
}
exit 0;
}
{
require Math::PlanePath::DiagonalsOctant;
require Math::PlanePath::PyramidRows;
my $diag = Math::PlanePath::DiagonalsOctant->new;
my $horiz = Math::PlanePath::PyramidRows->new (step => 1);
my $gcd = Math::PlanePath::GcdRationals->new;
my %seen;
my @xy;
foreach my $n (1 .. 99) {
my ($hx,$hy) = $horiz->n_to_xy($n) or die;
my $dn = $diag->xy_to_n($hx,$hy) // die;
# my ($hx,$hy) = $diag->n_to_xy($n) or die;
# my $dn = $horiz->xy_to_n($hx,$hy) // die;
### at: "n=$n hxy=$hx,$hy dn=$dn"
if ($seen{$dn}) {
die "saw $dn hxy=$hx,$hy from $seen{$dn} already";
}
$seen{$dn} = "n=$n,hxy=$hx,$hy";
# $dn = $n;
my ($x,$y) = $gcd->n_to_xy($dn);
$xy[$x][$y] = $n;
### store: "n=$n at $x,$y"
}
foreach my $y (0 .. 10) {
foreach my $x (0 .. 10) {
printf "%3s", $xy[$x][$y]//'.';
}
print "\n";
}
exit 0;
}
{
my $path = Math::PlanePath::GcdRationals->new;
require Math::Prime::XS;
my @primes = Math::Prime::XS::sieve_primes(10000);
my $fmax = 0;
foreach my $y (1 .. 5000) {
foreach my $x (1 .. 5000) {
my $n = $path->xy_to_n($x+1,$y+1) // next;
my $est = ($x+$y)**2 + $x;
my $f = $est / $n;
if ($f > $fmax + .5) {
print "$f\n";
$fmax = $f;
}
}
}
exit 0;
}
{
my $path = Math::PlanePath::GcdRationals->new;
foreach my $y (3 .. 50) {
foreach my $x (3 .. 50) {
my $n = $path->xy_to_n($x,$y) // next;
my $slope = int($x/$y) + 1;
my $g = $slope+1;
my $fn = $x*$g + $y*$g*(($y-2)*$g + 1)/2;
if ($n != $fn) {
### $n
### $fn
### $g
### $x
### $y
my $int = int($x/$y);
my $i = $x % $y;
if ($i == 0) {
$i = $y;
$int--;
}
$int++;
$i *= $int;
}
}
}
exit 0;
}
{
my $path = Math::PlanePath::GcdRationals->new;
foreach my $y (1 .. 500) {
my $prev_n = 0;
foreach my $x (1 .. 500) {
my $n = $path->xy_to_n($x,$y) // next;
if ($n <= $prev_n) {
die "not monotonic $n cf $prev_n";
}
$prev_n = $n;
}
}
exit 0;
}
{
my $path = Math::PlanePath::GcdRationals->new;
print "N =";
foreach my $n (1 .. 11) {
printf "%5d", $n;
}
print "\n";
print "X/Y =";
foreach my $n (1 .. 11) {
my ($x,$y) = $path->n_to_xy($n);
print " $x/$y,"
}
print " etc\n";
exit 0;
}
Math-PlanePath-113/devel/flowsnake-levels.pl 0000644 0001750 0001750 00000004416 11620710560 016617 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use Smart::Comments;
use Math::Libm 'M_PI', 'hypot';
use Math::Trig 'cartesian_to_cylindrical', 'cylindrical_to_cartesian';
use Math::PlanePath::Flowsnake;
my $path = Math::PlanePath::Flowsnake->new;
my $width = 300;
my $height = 300;
print <<"HERE";
]>
HERE
Math-PlanePath-113/devel/junk/ 0002755 0001750 0001750 00000000000 12255673733 013764 5 ustar gg gg Math-PlanePath-113/devel/junk/FibonacciSquareSpiral.pm 0000644 0001750 0001750 00000010430 12145611505 020512 0 ustar gg gg # Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Grows too quickly to be interesting.
#
# math-image --path=FibonacciSquareSpiral --lines --scale=10
# math-image --path=FibonacciSquareSpiral --output=numbers
# #------------------------------------------------------------------------------
# # A138710 - abs(dX) but OFFSET=1
#
# MyOEIS::compare_values
# (anum => 'A138710',
# func => sub {
# my ($count) = @_;
# my @got;
# for (my $n = $path->n_start; @got < $count; $n++) {
# my ($dx,$dy) = $path->n_to_dxdy($n);
# push @got, abs($dx);
# }
# return \@got;
# });
#
# # A138709 - abs(dY) but OFFSET=1
# MyOEIS::compare_values
# (anum => 'A138709',
# func => sub {
# my ($count) = @_;
# my @got;
# for (my $n = $path->n_start; @got < $count; $n++) {
# my ($dx,$dy) = $path->n_to_dxdy($n);
# push @got, abs($dy);
# }
# return \@got;
# });
package Math::PlanePath::FibonacciSquareSpiral;
use 5.004;
use strict;
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 104;
use Math::PlanePath 37;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'digit_split_lowtohigh';
# uncomment this to run the ### lines
#use Devel::Comments;
use constant default_n_start => 1;
sub new {
my $self = shift->SUPER::new (@_);
if (! defined $self->{'n_start'}) {
$self->{'n_start'} = $self->default_n_start;
}
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
#### SquareSpiral n_to_xy: $n
$n = $n - $self->{'n_start'}; # starting $n==0, warn if $n==undef
if ($n < 0) {
#### before n_start ...
return;
}
my $f0 = int($n)*0; # inherit BigInt zero
my $f1 = $f0 + 1; # inherit BigInt one
my $x = 0;
my $y = 0;
my $dx = 1;
my $dy = 0;
while ($n > $f1) {
$n -= $f1;
$x += $dx * $f1;
$y += $dy * $f1;
($f1,$f0) = ($f1+$f0,$f1);
($dx,$dy) = (-$dy,$dx); # rotate +90
}
return ($n*$dx + $x, $n*$dy + $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
### FibonacciSquareSpiral xy_to_n() ...
return undef;
}
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
return ($self->{'n_start'},
$self->{'n_start'} + max($x1,$x2,$y1,$y2)**2);
}
1;
__END__
=for stopwords eg Ryde
=head1 NAME
Math::PlanePath::FibonacciSquareSpiral -- spiral with Fibonacci number sides
=head1 SYNOPSIS
use Math::PlanePath::FibonacciSquareSpiral;
my $path = Math::PlanePath::FibonacciSquareSpiral->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
This path is ...
=head1 FUNCTIONS
See L for the behaviour common to all path
classes.
=over 4
=item C<$path = Math::PlanePath::FibonacciSquareSpiral-Enew ()>
Create and return a new path object.
=back
=head1 SEE ALSO
L,
L
=head1 HOME PAGE
http://user42.tuxfamily.org/math-planepath/index.html
=head1 LICENSE
Copyright 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/devel/hex-arms.pl 0000644 0001750 0001750 00000012701 12014333612 015053 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use List::Util qw(max);
use Devel::Comments;
{
require Math::PlanePath::DiamondArms;
my @max;
my $path = Math::PlanePath::DiamondArms->new;
foreach my $n (2 .. 10000) {
my ($x,$y) = $path->n_to_xy($n);
$x = abs($x);
$y = abs($y);
my $d = abs($x)+abs($y);
$max[$d] ||= 0;
$max[$d] = max($max[$d], $n);
}
### @max
exit 0;
}
{
require Math::PlanePath::HexArms;
my @max;
my $path = Math::PlanePath::HexArms->new;
foreach my $n (2 .. 10000) {
my ($x,$y) = $path->n_to_xy($n);
$x = abs($x);
$y = abs($y);
my $d = ($y >= $x
? $y # middle
: ($x + $y)/2); # end
$max[$d] ||= 0;
$max[$d] = max($max[$d], $n);
}
### @max
exit 0;
}
{
# cf A094268 smallest of N consecutive abundants
# 5775 pair (3,4 mod 6)
# 171078830 triplet (2,3,4 mod 6)
# 141363708067871564084949719820472453374 first run of 4 consecutive
#
# cf A047802 first abundant not using the first N primes
#
my $limit = 33426748355;
my $min = $limit;
my $divsum = 1;
for (my $p5 = 0; ; $p5++) {
my $value = 5**$p5;
last if $value > $limit;
my $divsum = (5**($p5+1) - 1) / 4;
for (my $p7 = 0; ; $p7++) {
my $value = $value * 7**$p7;
last if $value > $limit;
my $divsum = $divsum * (7**($p7+1) - 1) / 6;
for (my $p11 = 0; ; $p11++) {
my $value = $value * 11**$p11;
last if $value > $limit;
my $divsum = $divsum * (11**($p11+1) - 1) / 10;
for (my $p13 = 0; ; $p13++) {
my $value = $value * 13**$p13;
last if $value > $limit;
my $divsum = $divsum * (13**($p13+1) - 1) / 12;
for (my $p17 = 0; ; $p17++) {
my $value = $value * 17**$p17;
last if $value > $limit;
my $divsum = $divsum * (17**($p17+1) - 1) / 16;
for (my $p19 = 0; ; $p19++) {
my $value = $value * 19**$p19;
last if $value > $limit;
my $divsum = $divsum * (19**($p19+1) - 1) / 18;
for (my $p23 = 0; ; $p23++) {
my $value = $value * 23**$p23;
last if $value > $limit;
my $divsum = $divsum * (23**($p23+1) - 1) / 22;
for (my $p29 = 0; ; $p29++) {
my $value = $value * 29**$p29;
last if $value > $limit;
my $divsum = $divsum * (29**($p29+1) - 1) / 28;
for (my $p31 = 0; ; $p31++) {
my $value = $value * 31**$p31;
last if $value > $limit;
my $divsum = $divsum * (31**($p31+1) - 1) / 30;
if ($divsum > 2*$value) {
print "value $value divsum $divsum\n";
print "$p5 $p7 $p11 $p13 $p17 $p19 $p23 $p29 $p31\n";
if ($value < $min) {
print " smaller\n";
$min = $value;
}
print "\n";
last;
}
}
}
}
}
}
}
}
}
}
exit 0;
}
{
# 7^k divisors 1,...,7^k
# sum = (7^(k+1)-1)/6
# sum/7^k = (7 - 1/7^k) / 6
# -> 7/6
# single 1,7
# sum = 7+1 = 8
# sum/7 = 8/7
#
use Math::BigInt;
require Math::Prime::XS;
my @primes = Math::Prime::XS::sieve_primes(10000);
my $prod = 1;
my $value = 1;
# for (my $i = 7; $i < 1000; $i += 6) {
foreach my $i (@primes) {
if (($i % 6) != 1
&& ($i % 6) != 5
) {
next;
}
# my $f = $i/($i-1);
my $f = ($i+1)/$i;
$prod *= $f;
$value *= $i;
print "$i $prod\n";
if ($prod > 2) {
last;
}
}
print "value $value\n";
exit 0;
}
{
# 7^k divisors 1,...,7^k = (7^(k+1)-1)/6
use Math::BigInt;
foreach my $i (1 .. 200) {
foreach my $j (0 .. 10) {
foreach my $k (0 .. 10) {
my $n = Math::BigInt->new(7)**$i
* Math::BigInt->new(13)**$j
* Math::BigInt->new(19)**$k;
my $sd = (Math::BigInt->new(7)**($i+1) - 1) / 6
* (Math::BigInt->new(13)**($j+1) - 1) / 12
* (Math::BigInt->new(19)**($k+1) - 1) / 18;
if ($sd >= 2*$n) {
print "$i, $j $n $sd\n";
}
}
}
}
exit 0;
}
{
require Math::NumSeq::Abundant;
my $seq = Math::NumSeq::Abundant->new (hi => 5_000_000);
my ($max_i, $max_value);
while (my ($i, $value) = $seq->next) {
# my $m = ($value % 6);
# if ($m == 1 || $m == 5) {
# print "$i $value is $m mod 6\n";
# }
if ($value % 2) {
print "$i $value odd\n";
}
($max_i, $max_value) = ($i, $value);
}
print "to $max_i $max_value\n";
exit 0;
}
Math-PlanePath-113/devel/chan-tree.pl 0000644 0001750 0001750 00000012370 12155012130 015172 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use List::Util 'min', 'max';
use Math::PlanePath::ChanTree;
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh';
# uncomment this to run the ### lines
use Smart::Comments;
{
# gcd vs count ternary 1 digits
# ternary n_start=>1
# 1 2
# / | \ / | \
# 10 11 12 20 21 22
# / | \
# 100 101 102
require Math::PlanePath::GcdRationals;
require Math::NumSeq::DigitCount;
require Math::BaseCnv;
my $seq = Math::NumSeq::DigitCount->new (digit => 1, radix => 3);
my $k = 3;
my $path = Math::PlanePath::ChanTree->new
(k => $k,
n_start => 1,
);
my $n = $path->n_start;
my $prevlen = 1;
my $prev_gcd = 0;
for (;; $n++) {
my $nk = Math::BaseCnv::cnv($n,10,$k);
my $len = length($nk);
last if $len > 11;
if ($len > $prevlen) {
print "\n";
$prevlen = $len;
}
my ($x,$y) = $path->n_to_xy($n);
my $gcd = Math::PlanePath::GcdRationals::_gcd($x,$y);
my $offset3 = substr($nk,1);
my $offset = Math::BaseCnv::cnv($offset3,$k,10);
my $count = $seq->ith($offset);
my $pow = 3 ** max($count,0);
my $above = ($gcd == $pow && $count>0 ? " ===$pow"
: $gcd > $pow ? ' ***' : '');
if ($gcd > $prev_gcd) {
print "$n $nk $x / $y $gcd $pow (offset $offset) $above\n";
$prev_gcd = $gcd;
}
}
exit 0;
}
{
# X/Y list
require Math::PlanePath::GcdRationals;
require Math::PlanePath::PythagoreanTree;
my $pyth = Math::PlanePath::PythagoreanTree->new (coordinates => 'PQ',
tree_type => 'UAD');
require Math::BaseCnv;
my $k = 3;
my $path = Math::PlanePath::ChanTree->new
(k => $k,
n_start => 1,
);
my $n = $path->n_start;
my $prevlen = 1;
for (;; $n++) {
# my $depth = $path->tree_n_to_depth($n);
# my $n_row = $path->tree_depth_to_n($depth);
# my $n_end = $path->tree_depth_to_n_end($depth);
# my $n_half = ($n_row + $n_end + 1)/2;
# next unless $n >= $n_half;
my $nk = Math::BaseCnv::cnv($n,10,$k);
my $len = length($nk);
last if $len > 5;
if ($len > $prevlen) {
print "\n";
$prevlen = $len;
}
my ($x,$y) = $path->n_to_xy($n);
my $pyth_n = $pyth->xy_to_n($x,$y);
my $pyth_n3;
if (defined $pyth_n) {
$pyth_n3 = Math::BaseCnv::cnv($pyth_n,10,$k);
}
$pyth_n //= 'none';
$pyth_n3 //= 'none';
my $gcd = Math::PlanePath::GcdRationals::_gcd($x,$y);
my $xg = $x/$gcd;
my $yg = $y/$gcd;
print "$n $nk $x / $y $gcd reduced $xg,$yg $pyth_n3\n";
}
exit 0;
}
{
# 1 2 2
# 1 4 6 5 2 6 8 6 2 5 6 4 1 6 10 9 4 14 20 16 6 17 22 16 5 12 14 9
require Math::Polynomial;
Math::Polynomial->string_config({ ascending => 1 });
sub make_poly_k4 {
my ($level) = @_;
my $pow = 4**$level;
my $exp = 0;
my $ret = 0;
foreach my $coeff (1,2,2,1,2,2,1) {
$ret += Math::Polynomial->monomial ($exp, $coeff);
$exp += $pow;
}
return $ret;
}
print make_poly_k4(0),"\n";
print make_poly_k4(1),"\n";
my $poly = 1;
foreach my $level (0 .. 4) {
$poly *= make_poly_k4($level);
foreach my $i (0 .. 30) {
print " ",$poly->coeff($i);
}
print "\n";
}
exit 0;
}
{
# children formulas
foreach my $k (3 .. 8) {
my $half_ceil = int(($k+1) / 2);
foreach my $digit (0 .. $k-1) {
my $c1 = ($digit < $half_ceil ? $digit+1 : $k-$digit);
my $c0 = ($digit <= $half_ceil ? $digit : $k-$digit+1);
my $c2 = ($digit < $half_ceil-1 ? $digit+2 : $k-$digit-1);
print "${c1}x + ${c0}y / ${c2}x + ${c1}y\n";
}
print "\n";
}
exit 0;
}
{
# 1 2 3 2 1 4 7 8 5 2 7 12 13 8 3 8 13 12 7 2 5 8 7 4 1 6 11 14 9 4 15
require Math::Polynomial;
Math::Polynomial->string_config({ ascending => 1 });
sub make_poly_k5 {
my ($level) = @_;
my $pow = 5**$level;
my $exp = 0;
my $ret = 0;
foreach my $coeff (1,2,3,2,1,2,3,2,1) {
$ret += Math::Polynomial->monomial ($exp, $coeff);
$exp += $pow;
}
return $ret;
}
print make_poly_k5(0),"\n";
print make_poly_k5(1),"\n";
my $poly = 1;
foreach my $level (0 .. 4) {
$poly *= make_poly_k5($level);
foreach my $i (0 .. 30) {
print " ",$poly->coeff($i);
}
print "\n";
}
# (1 + 2*x + 3*x^2 + 2*x^3 + x^4 + 2*x^5 + 3*x^6 + 2*x^7 + x^8)
# * (1 + 2*x^5 + 3*x^10 + 2*x^15 + x^20 + 2*x^25 + 3*x^30 + 2*x^35 + x^40)
# * (1 + 2*x^(25*1) + 3*x^(25*2) + 2*x^(25*3) + x^(25*4) + 2*x^(25*5) + 3*x^(25*6) + 2*x^(25*7) + x^(25*8))
exit 0;
}
Math-PlanePath-113/devel/sierpinski-curve.pl 0000644 0001750 0001750 00000014616 12136646215 016653 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use POSIX ();
use Math::Trig 'pi';
use Math::PlanePath::SierpinskiArrowhead;
# uncomment this to run the ### lines
use Smart::Comments;
{
# dSumAbs
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => 'SierpinskiCurveStair,arms=6',
delta_type => 'dSumAbs');
for (1 .. 300) {
my ($i,$value) = $seq->next;
print "$value,";
if ($i % 6 == 5) {
print "\n";
}
}
exit 0;
}
{
# A156595 Mephisto Waltz first diffs xor as turns
require Tk;
require Tk::CanvasLogo;
require Math::NumSeq::MephistoWaltz;
my $top = MainWindow->new;
my $width = 1200;
my $height = 800;
my $logo = $top->CanvasLogo(-width => $width, -height => $height)->pack;
my $turtle = $logo->NewTurtle('foo');
$turtle->LOGO_PU();
$turtle->LOGO_FD(- $height/2*.9);
$turtle->LOGO_PD();
my $step = 5;
$turtle->LOGO_FD($step);
my $seq = Math::NumSeq::MephistoWaltz->new;
my ($i,$prev) = $seq->next;
for (;;) {
my ($i,$value) = $seq->next;
my $turn = $value ^ $prev;
$prev = $value;
last if $i > 10000;
if ($turn) {
$turtle->LOGO_FD($step);
if ($i & 1) {
$turtle->LOGO_RT(120);
} else {
$turtle->LOGO_LT(120);
}
} else {
$turtle->LOGO_FD($step);
}
$logo->createArc($turtle->{x}+2, $turtle->{y}+2,
$turtle->{x}-2, $turtle->{y}-2);
}
Tk::MainLoop();
exit;
}
{
# dX,dY
require Math::PlanePath::SierpinskiCurve;
my $path = Math::PlanePath::SierpinskiCurve->new;
foreach my $n (0 .. 32) {
# my $n = $n + 1/256;
my ($x,$y) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
my $sx = $x2-$x;
my $sy = $y2-$y;
my $sdir = dxdy_to_dir8($sx,$sy);
my ($dx,$dy) = $path->_WORKING_BUT_HAIRY__n_to_dxdy($n);
my $ddir = dxdy_to_dir8($dx,$dy);
my $diff = ($dx != $sx || $dy != $sy ? ' ***' : '');
print "$n $x,$y $sx,$sy\[$sdir] $dx,$dy\[$ddir]$diff\n";
}
# return 0..7
sub dxdy_to_dir8 {
my ($dx, $dy) = @_;
return atan2($dy,$dx) / atan2(1,1);
if ($dx == 1) {
if ($dy == 1) { return 1; }
if ($dy == 0) { return 0; }
if ($dy == -1) { return 7; }
}
if ($dx == 0) {
if ($dy == 1) { return 2; }
if ($dy == -1) { return 6; }
}
if ($dx == -1) {
if ($dy == 1) { return 3; }
if ($dy == 0) { return 4; }
if ($dy == -1) { return 5; }
}
die 'oops';
}
exit 0;
}
{
# Mephisto Waltz 1/12 slice of plane
require Tk;
require Tk::CanvasLogo;
require Math::NumSeq::MephistoWaltz;
my $top = MainWindow->new;
my $width = 1000;
my $height = 800;
my $logo = $top->CanvasLogo(-width => $width, -height => $height)->pack;
my $turtle = $logo->NewTurtle('foo');
$turtle->LOGO_RT(45);
$turtle->LOGO_PU();
$turtle->LOGO_FD(- $height*sqrt(2)/2*.9);
$turtle->LOGO_PD();
$turtle->LOGO_RT(135);
$turtle->LOGO_LT(30);
my $step = 5;
$turtle->LOGO_FD($step);
my $seq = Math::NumSeq::MephistoWaltz->new;
for (;;) {
my ($i,$value) = $seq->next;
last if $i > 10000;
if ($value) {
$turtle->LOGO_RT(60);
$turtle->LOGO_FD($step);
} else {
$turtle->LOGO_LT(60);
$turtle->LOGO_FD($step);
}
}
Tk::MainLoop();
exit;
}
{
require Tk;
require Tk::CanvasLogo;
require Math::NumSeq::PlanePathTurn;
my $top = MainWindow->new();
my $logo = $top->CanvasLogo->pack;
my $turtle = $logo->NewTurtle('foo');
my $seq = Math::NumSeq::PlanePathTurn->new
(planepath => 'KochCurve',
turn_type => 'Left');
$turtle->LOGO_RT(45);
$turtle->LOGO_FD(10);
for (;;) {
my ($i,$value) = $seq->next;
last if $i > 64;
if ($value) {
$turtle->LOGO_RT(45);
$turtle->LOGO_FD(10);
$turtle->LOGO_RT(45);
$turtle->LOGO_FD(10);
} else {
$turtle->LOGO_LT(90);
$turtle->LOGO_FD(10);
$turtle->LOGO_LT(90);
$turtle->LOGO_FD(10);
}
}
Tk::MainLoop();
exit;
}
{
# filled fraction
require Math::PlanePath::SierpinskiCurve;
require Number::Fraction;
my $path = Math::PlanePath::SierpinskiCurve->new;
foreach my $level (1 .. 20) {
my $Ntop = 4**$level / 2 - 1;
my ($x,$y) = $path->n_to_xy($Ntop);
my $Xtop = 3*2**($level-1) - 1;
$x == $Xtop or die "x=$x Xtop=$Xtop";
my $frac = $Ntop / ($x*($x-1)/2);
print " $level $frac\n";
}
my $nf = Number::Fraction->new(4,9);
my $limit = $nf->to_num;
print " limit $nf = $limit\n";
exit 0;
}
{
# filled fraction
require Math::PlanePath::SierpinskiCurveStair;
require Number::Fraction;
foreach my $L (1 .. 5) {
print "L=$L\n";
my $path = Math::PlanePath::SierpinskiCurveStair->new (diagonal_length=>$L);
foreach my $level (1 .. 10) {
my $Nlevel = ((6*$L+4)*4**$level - 4) / 3;
my ($x,$y) = $path->n_to_xy($Nlevel);
my $Xlevel = ($L+2)*2**$level - 1;
$x == $Xlevel or die "x=$x Xlevel=$Xlevel";
my $frac = $Nlevel / ($x*($x-1)/2);
print " $level $frac\n";
}
my $nf = Number::Fraction->new((12*$L+8),(3*$L**2+12*$L+12));
my $limit = $nf->to_num;
print " limit $nf = $limit\n";
}
exit 0;
}
{
my $path = Math::PlanePath::SierpinskiCurve->new;
my @rows = ((' ' x 79) x 64);
foreach my $n (0 .. 3 * 3**4) {
my ($x, $y) = $path->n_to_xy ($n);
$x += 32;
substr ($rows[$y], $x,1, '*');
}
local $,="\n";
print reverse @rows;
exit 0;
}
{
my @rows = ((' ' x 64) x 32);
foreach my $p (0 .. 31) {
foreach my $q (0 .. 31) {
next if ($p & $q);
my $x = $p-$q;
my $y = $p+$q;
next if ($y >= @rows);
$x += 32;
substr ($rows[$y], $x,1, '*');
}
}
local $,="\n";
print reverse @rows;
exit 0;
}
Math-PlanePath-113/devel/mephisto-waltz.logo 0000644 0001750 0001750 00000002552 12061163535 016655 0 ustar gg gg #!/usr/bin/ucblogo
;; Copyright 2012 Kevin Ryde
;;
;; This file is part of Math-PlanePath.
;;
;; Math-PlanePath 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, or (at your option) any later
;; version.
;;
;; Math-PlanePath 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 Math-PlanePath. If not, see .
;; cf A156595 xor adjacent mephisto waltz
;;
;;-----------------------------------------------------------------------------
to increment :var
make :var (thing :var)+1
end
to count.ternary.twos :n
localmake "count 0
while [:n <> 0] [
if [(remainder :n 3) = 2] [increment "count];
make "n int(:n/3)
]
output :count
end
to mephisto.turn.angle :n
output ifelse ((modulo (count.ternary.twos :n) 2) = 0) [60] [-60]
end
to mephisto :steps
right 90
left 45
penup
back 300
right 90
pendown
localmake "step.len 3
for [i 0 :steps 1] [
forward :step.len
left mephisto.turn.angle :i
]
end
mephisto 2000
Math-PlanePath-113/devel/grid.pl 0000644 0001750 0001750 00000002054 11423250646 014264 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# if (($self->{'show'}||'') eq 'dump-list') {
# foreach my $i (1 .. $n_pixels-1) {
# my ($x, $y) = $path->n_to_xy ($i);
# if (! defined $x) { last; }
# $x += $x_origin;
# $y += $y_origin;
# printf "%d %s,%s\n", $i, $x//'undef', $y//'undef';
# }
# exit 0;
# }
#
Math-PlanePath-113/devel/hypot.pl 0000644 0001750 0001750 00000005110 11767504527 014511 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use POSIX ();
use Math::PlanePath::Hypot;
use Math::PlanePath::HypotOctant;
{
# even equivalence
my $all = Math::PlanePath::HypotOctant->new (points => 'all');
my $even = Math::PlanePath::HypotOctant->new (points => 'even');
for (my $n = $all->n_start; $n < 300; $n++) {
my ($ex,$ey) = $even->n_to_xy($n);
my ($ax,$ay) = $all->n_to_xy($n);
my $cx = ($ex+$ey)/2;
my $cy = ($ex-$ey)/2;
my $diff = ($cx!=$ax || $cy!=$ay ? ' **' : '');
print "$n $ax,$ay $cx,$cy$diff\n";
}
exit 0;
}
{
my %comb;
my $limit = 1000;
my $xlimit = int(sqrt($limit / 2));
foreach my $x (1 .. $xlimit) {
foreach my $y (1 .. $x) {
my $h = $x*$x+$y*$y;
if ($h <= $limit) {
$comb{$h} = 1;
}
}
}
my @all = sort {$a<=>$b} keys %comb;
print join(',',@all),"\n";
print "all ",scalar(@all),"\n";
foreach my $h (keys %comb) {
foreach my $j (keys %comb) {
if ($j < $h
&& ($h % $j) == 0
&& is_int(sqrt($h / $j))) {
delete $comb{$h};
last;
}
}
}
my @comb = sort {$a<=>$b} keys %comb;
print join(',',@comb),"\n";
print "count ",scalar(@comb),"\n";
exit 0;
sub is_int {
return $_[0] == int $_[0];
}
}
{
my @seen_ways;
for (my $s = 1; $s < 1000; $s++) {
my $h = $s * $s;
my @ways;
for (my $x = 1; $x < $s; $x++) {
my $y = sqrt($h - $x*$x);
# if ($y < $x) {
# last;
# }
if ($x >= $y && $y == int($y)) {
push @ways, " $x*$x + $y*$y\n";
}
}
my $num_ways = scalar(@ways);
$seen_ways[$num_ways]
||= $seen_ways[$num_ways] = "$s*$s = $h $num_ways ways\n" . join('',@ways);
}
print grep {defined} @seen_ways;
exit 0;
}
{
for (1 .. 1000) {
Math::PlanePath::Hypot::_extend();
}
# $,="\n";
# print map {$_//'undef'} @Math::PlanePath::Hypot::hypot_to_n;
exit 0;
}
Math-PlanePath-113/devel/koch-snowflakes.pl 0000644 0001750 0001750 00000017721 12253427423 016445 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use warnings;
use Math::PlanePath::KochSnowflakes;
# uncomment this to run the ### lines
# use Smart::Comments;
{
# num angles taking points pairwise
#
# one direction, so modulo 180
# can go outside: 3,12,102,906,7980
# not going outside: 3,12,90,666
#
# both directions
# can go outside: 3,18,155,1370
# not going outside: 3,18,124,917,6445
# 12, one direction always X increasing
# 0,-1 12->6 south
# 1,-3 12->7
# 1,-1 12->11
# 2,-1 14->7
# 3,-1 12->10
# 5,-1 14->9
# 1,0 14->13 east
# 5,1 3,1 2,1 1,1 1,3
#
# 12
# / \
# 14----13 11----10
# \ /
# 15 9
# \
# 4---- 5 7---- 8
# \ /
# 6
require Math::Geometry::Planar;
my $path = Math::PlanePath::KochSnowflakes->new;
my @values;
require Math::PlanePath::GcdRationals;
foreach my $level (0 .. 7) {
my $n_level = 4**$level;
my $n_end = 4**($level+1) - 1;
my @points;
foreach my $n ($n_level .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
push @points, [$x,$y];
}
sub points_equal {
my ($p1, $p2) = @_;
return (abs($p1->[0] - $p2->[0]) < 0.00001
&& abs($p1->[1] - $p2->[1]) < 0.00001);
}
# Return true if line $p1--$p2 is entirely within the snowflake.
# If $p1--$p2 intersects any boundary segment then it's not entirely
# within.
#
# -3,-1 ---- -1,-1
my $segment_inside = sub {
my ($p1,$p2) = @_;
### segment_inside: join(',',@$p1).' '.join(',',@$p2)
foreach my $i (0 .. $#points) {
my $pint = Math::Geometry::Planar::SegmentIntersection([$p1,$p2, $points[$i-1],$points[$i]]) || next;
### intersects: join(',',@{$points[$i-1]}).' '.join(',',@{$points[$i]}).' at '.join(',',@$pint)
if (points_equal($pint,$p1) || points_equal($pint,$p1)
|| points_equal($pint,$points[$i-1]) || points_equal($pint,$points[$i])) {
### is an endpoint ...
next;
}
if (Math::Geometry::Planar::Colinear([$p1,$pint,$points[$i]])) {
### but colinear ...
next;
}
### no, crosses boundary ...
return 0;
}
### yes, all inside ...
return 1;
};
my %seen;
foreach my $i (0 .. $#points) {
foreach my $j ($i+1 .. $#points) {
### pair: "$i -- $j"
my $p1 = $points[$i];
my $p2 = $points[$j];
my $dx = $p1->[0] - $p2->[0];
my $dy = $p1->[1] - $p2->[1];
my $rdx = $dx;
my $rdy = $dy;
if ($rdx < 0 || ($rdx == 0 && $rdy < 0)) {
$rdx = -$rdx;
$rdy = -$rdy;
}
my $g = Math::PlanePath::GcdRationals::_gcd($rdx,$rdy);
$rdx /= $g;
$rdy /= $g;
next if $seen{"$rdx,$rdy"};
next unless $segment_inside->($p1, $p2);
$seen{"$rdx,$rdy"} = 1;
}
}
my $count = scalar(keys %seen);
if ($count <= 12) {
my @strs = keys %seen;
@strs = sort strpoint_cmp_by_atan2 @strs;
print join(' ',@strs),"\n";
}
push @values, $count;
print "$level $count\n";
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
sub strpoint_cmp_by_atan2 {
my ($ax,$ay) = split /,/, $a;
my ($bx,$by) = split /,/, $b;
return atan2($ay,$ax) <=> atan2($by,$bx);
}
}
{
# num acute angle turns, being num right hand turns
# A178789
my $path = Math::PlanePath::KochSnowflakes->new;
my @values;
require Math::NumSeq::PlanePathTurn;
foreach my $level (0 .. 8) {
my $n_level = 4**$level;
my $n_end = 4**($level+1) - 1;
my @x;
my @y;
foreach my $n ($n_level .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
push @x, $x;
push @y, $y;
}
my $count = 0;
foreach my $i (0 .. $#x) {
my $dx = $x[$i-1] - $x[$i-2];
my $dy = $y[$i-1] - $y[$i-2];
my $next_dx = $x[$i] - $x[$i-1];
my $next_dy = $y[$i] - $y[$i-1];
my $tturn6 = Math::NumSeq::PlanePathTurn::_turn_func_TTurn6($dx,$dy, $next_dx,$next_dy);
### $tturn6
if ($tturn6 == 2 || $tturn6 == 4) {
$count++;
}
}
$count = ($n_end - $n_level + 1) - $count; # non-acute ones
push @values, $count;
my $calc = 4**$level + 2;
print "$level $count $calc\n";
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
}
{
# num lines at 60deg angles, A110593 2*3^n
# 3,6,18,54,162
# 18*3=54
#
my $path = Math::PlanePath::KochSnowflakes->new;
my @values;
require Math::NumSeq::PlanePathDelta;
foreach my $level (0 .. 7) {
my $n_level = 4**$level;
my $n_end = 4**($level+1) - 1;
my %seen;
foreach my $n ($n_level .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my ($dx,$dy) = $path->n_to_dxdy($n);
if ($n == $n_end) {
my ($x2,$y2) = $path->n_to_xy($n_level);
$dx = $x2 - $x;
$dy = $y2 - $y;
}
my $tdir6 = Math::NumSeq::PlanePathDelta::_delta_func_TDir6($dx,$dy);
my $value;
if ($tdir6 % 3 == 0) {
$value = "H-$y";
} elsif ($tdir6 % 3 == 1) {
$value = "I-".($x-$y);
} else {
$value = "J-".($x+$y);
}
# print " $n $value\n";
$seen{$value} = 1;
}
my $count = scalar(keys %seen);
push @values, $count;
print "$level $count\n";
}
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
}
{
# area
require Math::Geometry::Planar;
my $path = Math::PlanePath::KochSnowflakes->new;
my @values;
my $prev_a_log = 0;
my $prev_len_log = 0;
# area of an equilateral triangle of side length 1
use constant AREA_EQUILATERAL_1 => sqrt(3)/4;
foreach my $level (0 .. 7) {
my $n_level = 4**$level;
my $n_end = 4**($level+1) - 1;
my @points;
foreach my $n ($n_level .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
# ($x,$y) = triangular_to_unit_side($x,$y);
push @points, [$x,$y];
}
my $polygon = Math::Geometry::Planar->new;
$polygon->points(\@points);
my $a = $polygon->area;
my $len = $polygon->perimeter;
# $a /= 3**$len;
# $len /= sqrt(3)**$len;
my $a_log = log($a);
my $len_log = log($len);
my $d_a_log = $a_log - $prev_a_log;
my $d_len_log = $len_log - $prev_len_log;
my $f = $d_a_log / $d_len_log;
# $a /= AREA_EQUILATERAL_1();
print "$level $a\n";
# print "$level $d_len_log $d_a_log $f\n";
push @values, $a;
$prev_a_log = $a_log;
$prev_len_log = $len_log;
}
shift @values;
use lib 'xt'; require MyOEIS;
print MyOEIS->grep_for_values(array => \@values);
exit 0;
sub triangular_to_unit_side {
my ($x,$y) = @_;
return ($x/2, $y*(sqrt(3)/2));
}
}
{
# area
print sqrt(48)/10,"\n";
my $sum = 0;
foreach my $level (1 .. 10) {
my $area = (1 + 3/9*$sum) * sqrt(3)/4;
print "$level $area\n";
$sum += (4/9)**$level;
}
exit 0;
}
{
# X axis N increasing
my $path = Math::PlanePath::KochSnowflakes->new;
my $prev_n = 0;
foreach my $x (0 .. 10000000) {
my $n = $path->xy_to_n($x,0) // next;
if ($n < $prev_n) {
print "decrease N at X=$x N=$n prev_N=$prev_n\n";
}
$prev_n = $n;
}
}
Math-PlanePath-113/devel/cellular-rule.pl 0000644 0001750 0001750 00000007114 12042067504 016106 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use strict;
use Math::PlanePath::CellularRule;
# uncomment this to run the ### lines
use Smart::Comments;
{
# A169707 rule 750
my %grid;
my $width = 40;
my $height = 40;
$grid{0,0} = 1;
foreach my $level (0 .. 40) {
print "level $level\n";
foreach my $y (reverse -$height .. $height) {
foreach my $x (-$width .. $width) {
print $grid{$x,$y} // ' ';
}
print "\n";
}
my %new_grid = %grid;
my $count_new = 0;
foreach my $y (-$height .. $height) {
foreach my $x (-$width .. $width) {
my $count = (($grid{$x-1,$y} || 0)
+ ($grid{$x+1,$y} || 0)
+ ($grid{$x,$y-1} || 0)
+ ($grid{$x,$y+1} || 0));
# print "$level $x,$y count=$count\n";
if ($count == 1 || $count == 3) {
$new_grid{$x,$y} = 1;
$count_new++;
}
}
}
print "count new $count_new\n";
%grid = %new_grid;
}
exit 0;
}
{
# compare path against Cellular::Automata::Wolfram values
require Cellular::Automata::Wolfram;
my $width = 50;
my $x_offset = int($width/2)-1;
my $num_of_gens = $x_offset - 1;
RULE: foreach my $rule (0 .. 255) {
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my $auto = Cellular::Automata::Wolfram->new
(rule=>$rule, width=>$width, num_of_gens=>$num_of_gens);
my $gens = $auto->{'gens'};
foreach my $y (0 .. $#$gens) {
my $auto_str = $gens->[$y];
my $path_str = '';
foreach my $i (0 .. length($auto_str)-1) {
my $x = $i - $x_offset;
$path_str .= ($x < -$y || $x > $y ? substr($auto_str,$i,1)
: $path->xy_is_visited($x,$y) ? '1' : '0');
}
if ($auto_str ne $path_str) {
print "$rule y=$y\n";
print "auto $auto_str\n";
print "path $path_str\n";
print "\n";
next RULE;
}
}
}
exit 0;
}
{
my $rule = 124;
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my @ys = (5..20);
@ys = map{$_*2+1} @ys;
my @ns = map{$path->xy_to_n(-$_,$_)
}@ys;
my @diffs = map {$ns[$_]-$ns[$_-1]} 1 .. $#ns;
print "[",join(',',@diffs),"]\n";
my @dds = map {$diffs[$_]-$diffs[$_-1]} 1 .. $#diffs;
print "[",join(',',@dds),"]\n";
exit 0;
}
{
my $rule = 57;
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my @ys = (5..20);
@ys = map{$_*2+1} @ys;
my @ns = map{$path->xy_to_n(-$_,$_)
}@ys;
my @diffs = map {$ns[$_]-$ns[$_-1]} 1 .. $#ns;
print "[",join(',',@diffs),"]\n";
my @dds = map {$diffs[$_]-$diffs[$_-1]} 1 .. $#diffs;
print "[",join(',',@dds),"]\n";
exit 0;
}
{
my $rule = 57;
my $path = Math::PlanePath::CellularRule->new(rule=>$rule);
my @ys = (5..10);
@ys = map{$_*2+1} @ys;
print "[",join(',',@ys),"]\n";
print "[",join(',',map{$path->xy_to_n(-$_,$_)
}@ys),"]\n";
exit 0;
}
Math-PlanePath-113/devel/peano.pl 0000644 0001750 0001750 00000015410 12136645623 014446 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
# uncomment this to run the ### lines
#use Smart::Comments;
{
# dx,dy on even radix
require Math::PlanePath::PeanoCurve;
require Math::BigInt;
require Math::BaseCnv;
foreach my $radix (4, 2, 6, 8) {
print "radix=$radix\n";
my $path = Math::PlanePath::PeanoCurve->new (radix => $radix);
my $limit = 4000000000;
{
my %seen_dx;
for my $len (0 .. 8) {
for my $high (1 .. $radix-1) {
my $n = Math::BigInt->new($high);
foreach (1 .. $len) { $n *= $radix; $n += $radix-1; }
my ($dx,$dy) = $path->n_to_dxdy($n);
$dx = abs($dx);
my ($x,$y) = $path->n_to_xy($n);
my $xr = Math::BaseCnv::cnv($x,10,$radix);
my $dr = Math::BaseCnv::cnv($dx,10,$radix);
my $nr = Math::BaseCnv::cnv($n,10,$radix);
print "N=$n [$nr] dx=$dx [$dr] x=[$xr]\n";
unless ($seen_dx{$dx}++) {
}
}
}
}
{
my %seen_dy;
for my $len (0 .. 8) {
for my $high (1 .. $radix-1) {
my $n = Math::BigInt->new($high);
foreach (1 .. $len) { $n *= $radix; $n += $radix-1; }
my ($dx,$dy) = $path->n_to_dxdy($n);
$dy = abs($dy);
unless ($seen_dy{$dy}++) {
my $dr = Math::BaseCnv::cnv($dy,10,$radix);
my $nr = Math::BaseCnv::cnv($n,10,$radix);
print "N=$n [$nr] dy=$dy [$dr]\n";
}
}
}
}
print "\n";
}
exit 0;
}
{
# abs(dY) = count low 2-digits, mod 2
# abs(dX) = opposite, 1-abs(dY)
# x x
# vertical when odd number of low 2s ..0222
# N+1 carry propagates to change ..1000
# y y
# high y+1 complements x from 0->2 so X unchanged
# Y becomes Y+1 02 -> 10, or if complement then Y-1 20 -> 12
#
my $radix = 3;
require Math::PlanePath::PeanoCurve;
require Math::NumSeq::PlanePathDelta;
require Math::NumSeq::DigitCountLow;
require Math::BigInt;
require Math::BaseCnv;
my $path = Math::PlanePath::PeanoCurve->new (radix => $radix);
my $seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'AbsdX');
my $cnt = Math::NumSeq::DigitCountLow->new (radix => 3, digit => 2);
foreach my $n (0 .. 40) {
my ($dx,$dy) = $path->n_to_dxdy($n);
my $absdx = abs($dx);
my $absdy = abs($dy);
my $c = $cnt->ith($n);
my $by_c = $c & 1;
my $diff = $absdy == $by_c ? '' : ' ***';
# my $n = $n+1;
my $nr = Math::BaseCnv::cnv($n,10,$radix);
printf "%3d %7s %2d,%2d low=%d%s\n",
$n, $nr, abs($dx),abs($dy), $c, $diff;
# print "$n,";
if ($absdx != 0) {
}
}
exit 0;
}
{
# Dir4 maximum
my $radix = 6;
require Math::PlanePath::PeanoCurve;
require Math::NumSeq::PlanePathDelta;
require Math::BigInt;
require Math::BaseCnv;
my $path = Math::PlanePath::PeanoCurve->new (radix => $radix);
my $seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'Dir4');
my $dir4_max = 0;
foreach my $n (0 .. 600000) {
# my $n = Math::BigInt->new(2)**$level - 1;
my $dir4 = $seq->ith($n);
if ($dir4 > $dir4_max) {
$dir4_max = $dir4;
my ($dx,$dy) = $path->n_to_dxdy($n);
my $nr = Math::BaseCnv::cnv($n,10,$radix);
printf "%7s %2b,\n %2b %8.6f\n", $nr, abs($dx),abs($dy), $dir4;
}
}
exit 0;
}
{
# axis increasing
my $radix = 4;
my $rsquared = $radix * $radix;
my $re = '.' x $radix;
require Math::NumSeq::PlanePathN;
foreach my $line_type ('Y_axis', 'X_axis', 'Diagonal') {
OUTER: foreach my $serpentine_num (0 .. 2**$rsquared-1) {
my $serpentine_type = sprintf "%0*b", $rsquared, $serpentine_num;
# $serpentine_type = reverse $serpentine_type;
$serpentine_type =~ s/($re)/$1_/go;
### $serpentine_type
my $seq = Math::NumSeq::PlanePathN->new
(
planepath => "WunderlichSerpentine,radix=$radix,serpentine_type=$serpentine_type",
line_type => $line_type,
);
### $seq
# my $path = Math::NumSeq::PlanePathN->new
# (
# e,radix=$radix,serpentine_type=$serpentine_type",
# line_type => $line_type,
# );
my $prev = -1;
for (1 .. 1000) {
my ($i, $value) = $seq->next;
if ($value <= $prev) {
# print "$line_type $serpentine_type decrease at i=$i value=$value cf prev=$prev\n";
# my $path = $seq->{'planepath_object'};
# my ($prev_x,$prev_y) = $path->n_to_xy($prev);
# my ($x,$y) = $path->n_to_xy($value);
# # print " N=$prev $prev_x,$prev_y N=$value $x,$y\n";
next OUTER;
}
$prev = $value;
}
print "$line_type $serpentine_type all increasing\n";
}
}
exit 0;
}
{
# max Dir4
my $radix = 4;
require Math::BaseCnv;
print 4-atan2(2,1)/atan2(1,1)/2,"\n";
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => "PeanoCurve,radix=$radix",
delta_type => 'Dir4');
my $dx_seq = Math::NumSeq::PlanePathDelta->new (planepath => "PeanoCurve,radix=$radix",
delta_type => 'dX');
my $dy_seq = Math::NumSeq::PlanePathDelta->new (planepath => "PeanoCurve,radix=$radix",
delta_type => 'dY');
my $max = 0;
for (1 .. 10000000) {
my ($i, $value) = $seq->next;
# foreach my $k (1 .. 1000000) {
# my $i = $radix ** (4*$k+3) - 1;
# my $value = $seq->ith($i);
if ($value > $max
# || $i == 0b100011111
) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dy ? $dx/$dy : -1;
printf "%d %s %.5f %s %s %.3f\n", $i, $ri, $value, $rdx,$rdy, $f;
$max = $value;
}
}
exit 0;
}
Math-PlanePath-113/devel/theodorus.gnuplot 0000644 0001750 0001750 00000002101 11463457477 016440 0 ustar gg gg # Copyright 2010 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
set terminal xterm
# set xlabel "Days ago (0 today, 1 yesterday, etc)" 0, -2
#
# something evil happens with "xtics axis", need dummy xlabel
# set xlabel " " 0, -2
# set xrange [-0.5:39.5]
# set xtics axis 5
# set mxtics 5
# set ylabel "Weight (percent)"
#
#set yrange [-5:55]
#set format y "%.1f"
#unset key
#set style fill solid 1.0
#set boxwidth 0.6 relative
plot "/tmp/theodorus.data"
Math-PlanePath-113/devel/imaginary-base.pl 0000644 0001750 0001750 00000014750 12003102512 016214 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
use Math::PlanePath::Base::Generic
'is_infinite';
use Math::PlanePath::Base::Digits
'round_down_pow',
'digit_split_lowtohigh',
'digit_join_lowtohigh';
use Math::PlanePath::ImaginaryBase;
# uncomment this to run the ### lines
use Smart::Comments;
{
# nega min/max level
my $radix = 3;
# for (my $x2 = 0; $x2 < 100; $x2++) {
# _negaradix_range_digits($radix, $x2,$x2);
# }
# for (my $x1 = -1; $x1 > -100; $x1--) {
# _negaradix_range_digits($radix, $x1,$x1);
# }
for (my $x1 = 0; $x1 > -100; $x1--) {
for (my $x2 = 0; $x2 < 1; $x2++) {
my ($len, $level, $base)
= Math::PlanePath::ImaginaryBase::_negaradix_range_level($x1,$x2, $radix);
my $want_xmin = _level_to_xmin($level,$radix);
my $want_xmax = _level_to_xmax($level,$radix);
$len == $radix ** $level or die;
print "$x1 $want_xmin len=$len, level=$level, base=$base\n";
# print "$x2 $want_xmax len=$len, level=$level, base=$base\n";
unless ($base <= $x1 && $base+$len > $x2) {
print "$x1..$x2 got len=$len, level=$level, base=$base not cover\n";
}
}
}
exit 0;
}
{
my $radix = 4;
foreach my $level (0 .. 10) {
my $xmin = _level_to_xmin($level,$radix);
my $xmax = _level_to_xmax($level,$radix);
print "$level $xmin $xmax\n";
}
# Xmin = r*(r-1) + r^2 + r^4 + r^6
# Xmax = r-1 + r^2 + r^4 + r^6
# Xmax = 1 + (4^(k+1) - 1) / (4-1)
# k+1 = round down pow (X-1)*(R2-1) + 1
# 0,1,5,21
sub _level_to_xmax {
my ($level, $radix) = @_;
my $max = 0;
for (my $i = 1; $i < $level; $i += 2) {
$max += ($radix-1) * $radix ** ($i-1)
}
return $max;
my $rsquared = $radix*$radix; # r2 = radix**2
return ($radix**(2*$level) - 1) / ($rsquared-1);
return ($radix * $rsquared**$level + 1) / ($rsquared-1);
}
# -Xmin = 1 + R*(R2^(k+1) - 1) / (R2-1)
# R2^(k+2) = (X-1)*(R2-1)*R + R2
# 0,-2,-10,-42
sub _level_to_xmin {
my ($level, $radix) = @_;
my $min = 0;
for (my $i = 1; $i < $level; $i += 2) {
$min -= ($radix-1) * $radix ** $i;
}
return $min;
my $rsquared = $radix*$radix; # rsquared = radix**2
return 1 - ($radix**(2*$level+1) + 1) / ($rsquared-1);
return 1 - ($radix * $rsquared**$level + 1) / ($rsquared-1);
}
exit 0;
}
{
# nega min/max
#
my $radix = 4;
# for (my $x2 = 0; $x2 < 100; $x2++) {
# _negaradix_range_digits($radix, $x2,$x2);
# }
# for (my $x1 = -1; $x1 > -100; $x1--) {
# _negaradix_range_digits($radix, $x1,$x1);
# }
for (my $x1 = 0; $x1 > -1; $x1--) {
foreach my $x2 (0 .. 1) {
my ($min_digits, $max_digits)
= Math::PlanePath::ImaginaryBase::_negaradix_range_digits_lowtohigh($x1,$x2, $radix);
my $min = digit_join_lowtohigh ($min_digits, $radix);
my $max = digit_join_lowtohigh ($max_digits, $radix);
my ($want_min, $want_max)
= negaradix_index_range($x1,$x2, $radix);
if ($min != $want_min || $max != $want_max) {
print "$x1..$x2 got $min,$max want $want_min,$want_max\n";
print " min_digits ",join(',',@$min_digits),"\n";
print " max_digits ",join(',',@$max_digits),"\n";
}
}
}
exit 0;
}
{
# nega conversions
my $radix = 2;
my %seen;
foreach my $n (0 .. 1024) {
my $nega = index_to_negaradix($n,$radix);
if ($seen{$nega}++) {
print "duplicate nega=$nega\n";
}
my $rev_n = negaradix_to_index($nega,$radix);
if ($rev_n != $n) {
print "rev_n=$rev_n want n=$n\n";
}
print "$n $nega $rev_n\n";
}
sub index_to_negaradix {
my ($n, $radix) = @_;
my $power = 1;
my $ret = 0;
while ($n) {
my $digit = $n % $radix; # low to high
$n = int($n/$radix);
$ret += $power * $digit;
$power *= -$radix;
}
return $ret;
}
sub negaradix_to_index {
my ($n, $radix) = @_;
my $power = 1;
my $ret = 0;
while ($n) {
my $digit = $n % $radix; # low to high
$ret += $power * $digit;
$n = - int(($n-$digit)/$radix);
$power *= $radix;
}
return $ret;
}
sub negaradix_index_range {
my ($nega1, $nega2, $radix) = @_;
my @indices = map {negaradix_to_index($_,$radix)} $nega1 .. $nega2;
return (min(@indices), max(@indices));
}
exit 0;
}
{
# "**" operator
for (my $n = 1; $n < 0xFFFFFFFF; $n = 2*$n+1) {
my $cube = $n ** 3;
my $mod = $cube % $n;
print "$cube $mod\n";
}
exit 0;
}
{
# max Dir4
require Math::BaseCnv;
print 4-atan2(2,1)/atan2(1,1)/2,"\n";
require Math::NumSeq::PlanePathDelta;
my $radix = 8;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath => "ImaginaryBase,radix=$radix",
delta_type => 'Dir4');
my $dx_seq = Math::NumSeq::PlanePathDelta->new (planepath => "ImaginaryBase,radix=$radix",
delta_type => 'dX');
my $dy_seq = Math::NumSeq::PlanePathDelta->new (planepath => "ImaginaryBase,radix=$radix",
delta_type => 'dY');
my $max = 0;
# for (1 .. 1000000) {
# my ($i, $value) = $seq->next;
foreach my $k (1 .. 1000000) {
my $i = $radix ** (4*$k+3) - 1;
my $value = $seq->ith($i);
if ($value > $max) {
my $dx = $dx_seq->ith($i);
my $dy = $dy_seq->ith($i);
my $ri = Math::BaseCnv::cnv($i,10,$radix);
my $rdx = Math::BaseCnv::cnv($dx,10,$radix);
my $rdy = Math::BaseCnv::cnv($dy,10,$radix);
my $f = $dx/$dy;
printf "%d %s %.5f %s %s %.3f\n", $i, $ri, $value, $rdx,$rdy, $f;
$max = $value;
}
}
exit 0;
}
# $aref->[0] high digit
sub digit_join_hightolow {
my ($aref, $radix, $zero) = @_;
my $n = (defined $zero ? $zero : 0);
foreach my $digit (@$aref) {
$n *= $radix;
$n += $digit;
}
return $n;
}
Math-PlanePath-113/devel/dragon.el 0000644 0001750 0001750 00000012242 12061742360 014574 0 ustar gg gg ;; Copyright 2012 Kevin Ryde
;;
;; This file is part of Math-PlanePath.
;;
;; Math-PlanePath 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, or (at your option) any later
;; version.
;;
;; Math-PlanePath 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 Math-PlanePath. If not, see .
;; =={{header|Emacs Lisp}}==
;; Drawing ascii art characters into a buffer using picture-mode.
;;
;;
;;-----------------------------------------------------------------------------
;; by turns
;;
;; ;;-----------------------------------------------------------------------------
;; ;; by direction
;;
;;
;; (defun count-1bits (n)
;; "Return the number of 1-bits in N.
;; For example N=22 returns 3, since 22 in binary is \"10110\" which
;; has 3 1-bits."
;; (let ((count 0))
;; (while (not (zerop n))
;; ;; (setq n (logxor n (1- n))
;; (setq count (+ count (logand n 1)))
;; (setq n (lsh n -1)))
;; count))
;;
;; (defun count-bit-runs (n)
;; "Return the number of runs of the same bits in N.
;; For example N=27 is binary \"11011\" has three runs \"11\", \"0\", \"11\".
;; N=0 has 0 runs."
;; ;; xor with bits shifted to the right leaves a 1 at each transition
;; (count-1bits (logxor n (lsh n -1))))
;;
;; (defun dragon-direction (n)
;; "Return the direction 0,1,2,3 of the dragon curve at point N.
;; The return is 0=east, 1=north, 2=west, 3=south."
;; (logand 3 (count-bit-runs n)))
;;
;; (defun dragon-direction-vh (n)
;; "Return a list (vert horiz) of the dragon curve step at N.
;; vert and horiz are +1, -1 or 0, in the style of
;; `pointer-set-motion', which means vert=-1 is up the page, vert=+1
;; down the page. N=0 is the first point of the curve, which is to
;; the left so vert=0 horiz=+1 there."
;; (aref [(0 1) (-1 0) (0 -1) (1 0)] (dragon-direction n)))
;;
;; (defun dragon-picture (len step)
;; (interactive (list (read-number "Length of curve (default 256) " 256)
;; (read-number "Each step size (default 3 chars) " 3)))
;; (unless (>= step 1)
;; (error "Step length must be >= 1"))
;;
;; (switch-to-buffer "*dragon*")
;; (erase-buffer)
;; (ignore-errors (picture-mode))
;; (dotimes (n len) ;; 0 to len-1, inclusive
;; ;; direction of the curve at n
;; (apply 'picture-set-motion (dragon-direction-vh n))
;;
;; ;; draw corner "+" and if step>=2 then line "|" or "-" chars too
;; (dragon-insert-char ?+ 1)
;; (dragon-insert-char (if (zerop picture-vertical-step)
;; picture-rectangle-h
;; picture-rectangle-v)
;; (1- step))
;;
;; ;; delay to make the drawing visible as it progresses
;; (sit-for .01))
;;
;; (dragon-insert-char ?+ 1) ;; endpoint
;; (picture-mode-exit)
;; (goto-char (point-min)))
;;
;; ;; `M-x dragon-picture' to make a buffer with the dragon curve
;;
;;
;;
;;
;; ;;-----------------------------------------------------------------------------
;;
;;
;;
;;
;; (mapcar 'dragon-direction (number-sequence 0 16))
;;
;; (defmacro dragon-with-picture-mode (&rest body)
;; "Evaluate BODY with `picture-mode' enabled."
;; `(progn
;; (picture-mode)
;; (unwind-protect
;; (progn ,@body)
;; (picture-mode-exit))))
;;
;; (defconst dir-to-dx [1 0 -1 0]
;; "Vector of +1,-1,0 for X step in direction 0,1,2,3.")
;; (defconst dir-to-dy [0 -1 0 1]
;; "Vector of +1,-1,0 for Y step in direction 0,1,2,3.")
;;
;;
;; ;;-----------------------------------------------------------------------------
;;
;;
;; (progn
;; (defun dragon-insert-char (char step)
;; (dotimes (i step)
;; (if (= (current-column) 0) ;; in first column
;; (save-excursion (goto-char (point-min)) (replace-regexp "^" " ")))
;; (if (= (point-min) (line-beginning-position)) ;; on first line
;; (save-excursion (goto-char (point-min)) (insert "\n")))
;; ;; (picture-update-desired-column t)
;; (picture-insert char 1)
;; (sit-for .005)))
;;
;; (dragon-picture 8 3))
;;
;; (shell-command "math-image --expression='i<32?i:0' --path=DragonCurve --scale=20")
;;
;; ;; (picture-forward-column 40)
;; ;; (picture-move-down 40)
;;
;; (if (= 0 (current-column))
;; (save-excursion (rect
;;
;; # find which side to turn based on the iteration
;; $angle +=
;;
;; my ($dx, $dy) = ($x + $len * $angle.sin, $y - $len * $angle.cos);
;; say "";
;; ($x, $y) = ($dx, $dy);
;; }
;;
;;
;; (dotimes (i (1- (lsh 1 5)))
;; (let ((right (zerop (logand i (lsh (1+ (logxor i (1+ i))) 0)))))
;; (insert (if right "1" "0"))))
;;
;; ;; (insert (format "%S\n" (1+ (logxor i (1+ i))))))
;;
;;
;; 110110011100100111011000
;;
Math-PlanePath-113/devel/graph.pl 0000644 0001750 0001750 00000004605 12064255241 014442 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
# uncomment this to run the ### lines
use Smart::Comments;
{
# require Math::PlanePath::SierpinskiTriangle;
# my $path = Math::PlanePath::SierpinskiTriangle->new;
require Math::PlanePath::ToothpickTree;
my $path = Math::PlanePath::ToothpickTree->new;
my $depth = 5;
my $n_lo = $path->n_start;
my $n_hi = $path->tree_depth_to_n_end($depth);
require Graph::Easy;
my $graph = Graph::Easy->new();
foreach my $n ($n_lo .. $n_hi) {
foreach my $c ($path->tree_n_children($n)) {
$graph->add_edge($n,$c);
}
}
print "$graph\n";
print $graph->as_ascii;
print $graph->as_graphviz();
exit 0;
}
{
require Graph;
my $depth = 4;
my $path = Math::PlanePath::SierpinskiTriangle->new;
my $n_lo = $path->n_start;
my $n_hi = $path->tree_depth_to_n_end($depth);
my $graph = Graph->new (vertices => [ $n_lo .. $n_hi ],
edges => [ map { my $n = $_;
map { [ $n, $_ ] }
$path->tree_n_children($n)
}
$n_lo .. $n_hi ]);
print "$graph\n";
### cyclic: $graph->is_cyclic
### acyclic: $graph->is_acyclic
### all_successors: $graph->all_successors($n_lo)
### neighbours: $graph->neighbours($n_lo)
### interior_vertices: $graph->interior_vertices
### exterior_vertices: $graph->exterior_vertices
print "in_degree: ",join(',',map{$graph->in_degree($_)}$n_lo..$n_hi),"\n";
print "out_degree: ",join(',',map{$graph->out_degree($_)}$n_lo..$n_hi),"\n";
print "num_children: ",join(',',map{$path->tree_n_num_children($_)}$n_lo..$n_hi),"\n";
exit 0;
}
Math-PlanePath-113/devel/digit-groups.pl 0000644 0001750 0001750 00000011112 12000734245 015741 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use Math::PlanePath::Base::Digits 'digit_split_lowtohigh';
# uncomment this to run the ### lines
use Smart::Comments;
{
# 2^64-1 base7 45012021522523134134601
# decimal less first digit 2635249153387078802
# 2635249153387078656
require Devel::Peek;
my $n = ~0;
my $radix = 7;
my $digit = $n % $radix;
### $digit
$n /= $radix;
Devel::Peek::Dump($n);
$n = int($n);
Devel::Peek::Dump($n);
require Math::PlanePath;
my @digits = digit_split_lowtohigh(~0,$radix);
### @digits
exit 0;
}
{
# Diagonal
require Math::BaseCnv;
require Math::NumSeq::PlanePathN;
my $seq = Math::NumSeq::PlanePathN->new (planepath=> 'DigitGroups',
line_type => 'Diagonal');
foreach my $i (0 .. 150) {
my ($i,$value) = $seq->next;
my $v2 = Math::BaseCnv::cnv($value,10,2);
printf "%4d %20s\n", $value, $v2;
}
print "\n";
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::DigitGroups;
foreach my $radix (2 .. 7) {
print "radix $radix\n";
my $path = Math::PlanePath::DigitGroups->new (radix => $radix);
foreach my $coord_max (0 .. 25) {
my $n_max = $path->xy_to_n(0,0);
my $x_max = 0;
my $y_max = 0;
foreach my $x (0 .. $coord_max) {
foreach my $y (0 .. $coord_max) {
my $n = $path->xy_to_n($x,$y);
### got: "$x,$y $n"
if ($n > $n_max) {
$x_max = $x;
$y_max = $y;
$n_max = $n;
}
}
}
my $n_max_base = Math::BaseCnv::cnv($n_max,10,$radix);
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$coord_max,$coord_max);
my $n_hi_base = Math::BaseCnv::cnv($n_hi,10,$radix);
print " $coord_max $x_max,$y_max n=$n_max [$n_max_base] cf nhi=$n_hi [$n_hi_base]\n";
}
print "\n";
}
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::DigitGroups;
foreach my $radix (2 .. 7) {
print "radix $radix\n";
my $path = Math::PlanePath::DigitGroups->new (radix => $radix);
foreach my $exp (1 .. 5) {
my $coord_min = $radix ** ($exp-1);
my $coord_max = $radix ** $exp - 1;
print " $coord_min $coord_max\n";
my $x_min = $coord_min;
my $y_min = $coord_min;
my $n_min = $path->xy_to_n($x_min,$y_min);
foreach my $x ($coord_min .. $coord_max) {
foreach my $y ($coord_min .. $coord_max) {
my $n = $path->xy_to_n($x,$y);
### got: "$x,$y $n"
if ($n < $n_min) {
$x_min = $x;
$y_min = $y;
$n_min = $n;
}
}
}
my $n_min_base = Math::BaseCnv::cnv($n_min,10,$radix);
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$coord_max,$coord_max);
my $n_lo_base = Math::BaseCnv::cnv($n_lo,10,$radix);
print " $exp $x_min,$y_min n=$n_min [$n_min_base] cf nlo=$n_lo [$n_lo_base]\n";
}
print "\n";
}
exit 0;
}
{
require Math::BaseCnv;
require Math::PlanePath::DigitGroups;
foreach my $radix (2 .. 7) {
print "radix $radix\n";
my $path = Math::PlanePath::DigitGroups->new (radix => $radix);
foreach my $exp (1 .. 5) {
my $coord_max = $radix ** $exp - 1;
my $n_max = $path->xy_to_n(0,0);
my $x_max = 0;
my $y_max = 0;
foreach my $x (0 .. $coord_max) {
foreach my $y (0 .. $coord_max) {
my $n = $path->xy_to_n($x,$y);
### got: "$x,$y $n"
if ($n > $n_max) {
$x_max = $x;
$y_max = $y;
$n_max = $n;
}
}
}
my $n_max_base = Math::BaseCnv::cnv($n_max,10,$radix);
my ($n_lo, $n_hi) = $path->rect_to_n_range(0,0,$coord_max,$coord_max);
my $n_hi_base = Math::BaseCnv::cnv($n_hi,10,$radix);
print " $exp $x_max,$y_max n=$n_max [$n_max_base] cf nhi=$n_hi [$n_hi_base]\n";
}
print "\n";
}
exit 0;
}
Math-PlanePath-113/devel/imaginary-half.pl 0000644 0001750 0001750 00000005465 12003406621 016227 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use List::Util 'min', 'max';
# uncomment this to run the ### lines
#use Smart::Comments;
{
# Dir4 maximum
my $radix = 3;
require Math::PlanePath::ImaginaryHalf;
require Math::NumSeq::PlanePathDelta;
require Math::BigInt;
require Math::BaseCnv;
my $path = Math::PlanePath::ImaginaryHalf->new (radix => $radix);
my $seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'Dir4');
my $dir4_max = 0;
foreach my $n (0 .. 600000) {
# my $n = Math::BigInt->new(2)**$level - 1;
my $dir4 = $seq->ith($n);
if ($dir4 > $dir4_max) {
$dir4_max = $dir4;
my ($dx,$dy) = $path->n_to_dxdy($n);
my $nr = Math::BaseCnv::cnv($n,10,$radix);
printf "%d %7s %2d,%2d %8.6f\n", $n,$nr, ($dx),($dy), $dir4;
}
}
exit 0;
}
{
# ProthNumbers
require Math::BaseCnv;
require Math::PlanePath::ImaginaryHalf;
require Math::NumSeq::ProthNumbers;
$|=1;
my $radix = 2;
my $path = Math::PlanePath::ImaginaryHalf->new (radix => $radix);
my $seq = Math::NumSeq::ProthNumbers->new;
my %seen;
for (1 .. 200) {
my (undef, $n) = $seq->next;
my ($x, $y) = $path->n_to_xy($n);
my $n2 = Math::BaseCnv::cnv($n,10,$radix);
print "$x $y $n $n2\n";
$seen{$x} .= " ${y}[$n2]";
}
foreach my $x (sort {$a<=>$b} keys %seen) {
print "$x $seen{$x}\n";
}
exit 0;
}
{
# min/max extents
require Math::BaseCnv;
require Math::PlanePath::ImaginaryHalf;
$|=1;
my $radix = 3;
my $path = Math::PlanePath::ImaginaryHalf->new (radix => $radix);
my $xmin = 0;
my $xmax = 0;
my $ymax = 0;
my $n = $path->n_start;
for (my $level = 1; $level < 25; $level++) {
my $n_next = $radix**$level;
for ( ; $n < $n_next; $n++) {
my ($x,$y) = $path->n_to_xy($n);
$xmin = min ($xmin, $x);
$xmax = max ($xmax, $x);
$ymax = max ($ymax, $y);
}
printf "%2d %12s %12s %12s\n",
$level,
Math::BaseCnv::cnv($xmin,10,$radix),
Math::BaseCnv::cnv($xmax,10,$radix),
Math::BaseCnv::cnv($ymax,10,$radix);
}
exit 0;
}
Math-PlanePath-113/devel/alternate-paper-midpoint.pl 0000644 0001750 0001750 00000015210 12023012405 020224 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Usage: perl alternate-paper-midpoint.pl
#
# Print state tables used by Math::PlanePath::AlternatePaperMidpoint.
#
use 5.010;
use strict;
# uncomment this to run the ### lines
#use Smart::Comments;
sub print_table {
my ($name, $aref) = @_;
print "my \@$name = (";
my $entry_width = max (map {length($_//'')} @$aref);
foreach my $i (0 .. $#$aref) {
printf "%*s", $entry_width, $aref->[$i]//'undef';
if ($i == $#$aref) {
print ");\n";
} else {
print ",";
if (($i % 16) == 15
|| ($entry_width >= 3 && ($i % 4) == 3)) {
print "\n ".(" " x length($name));
} elsif (($i % 4) == 3) {
print " ";
}
}
}
}
my @next_state;
my @state_to_dxdy;
sub make_state {
my %param = @_;
my $state = 0;
$state <<= 1; $state |= delete $param{'nextturn'}; # high
$state <<= 2; $state |= delete $param{'rot'};
$state <<= 1; $state |= delete $param{'prevbit'};
$state <<= 2; $state |= delete $param{'digit'}; # low
if (%param) { die; }
return $state;
}
sub state_string {
my ($state) = @_;
my $digit = $state & 3; $state >>= 2;
my $prevbit = $state & 1; $state >>= 1;
my $rot = $state & 3; $state >>= 2;
my $nextturn = $state & 1; $state >>= 1;
return "rot=$rot prevbit=$prevbit (digit=$digit)";
}
foreach my $nextturn (0, 1) {
foreach my $rot (0, 1, 2, 3) {
foreach my $prevbit (0, 1) {
my $state = make_state (nextturn => $nextturn,
rot => $rot,
prevbit => $prevbit,
digit => 0);
### $state
foreach my $digit (0 .. 3) {
my $new_nextturn = $nextturn;
my $new_prevbit = $digit;
my $new_rot = $rot;
if ($digit != $prevbit) { # count 0<->1 transitions
$new_rot++;
$new_rot &= 3;
}
# nextturn from bit above lowest 0
if ($digit == 0) {
$new_nextturn = $prevbit ^ 1;
} elsif ($digit == 1) {
$new_nextturn = $prevbit;
} elsif ($digit == 2) {
$new_nextturn = 0; # 1-bit at odd position
}
my $dx = 1;
my $dy = 0;
if ($rot & 2) {
$dx = -$dx;
$dy = -$dy;
}
if ($rot & 1) {
($dx,$dy) = (-$dy,$dx); # rotate +90
}
### rot to: "$dx, $dy"
my $next_dx = $dx;
my $next_dy = $dy;
if ($nextturn) {
($next_dx,$next_dy) = ($next_dy,-$next_dx); # right, rotate -90
} else {
($next_dx,$next_dy) = (-$next_dy,$next_dx); # left, rotate +90
}
my $frac_dx = $next_dx - $dx;
my $frac_dy = $next_dy - $dy;
my $masked_state = $state & 0x1C;
$state_to_dxdy[$masked_state] = $dx;
$state_to_dxdy[$masked_state + 1] = $dy;
$state_to_dxdy[$masked_state + 2] = $frac_dx;
$state_to_dxdy[$masked_state + 3] = $frac_dy;
my $next_state = make_state
(nextturn => $new_nextturn,
rot => $new_rot,
prevbit => $new_prevbit,
digit => 0);
$next_state[$state+$digit] = $next_state;
}
}
}
}
### @next_state
### @state_to_dxdy
### next_state length: 4*(4*2*2 + 4*2)
print "# next_state length ", scalar(@next_state), "\n";
print_table ("next_state", \@next_state);
print_table ("state_to_dxdy", \@state_to_dxdy);
print "\n";
{
my @pending_state = (0, 4, 8, 12); # in 4 arm directions
my $count = 0;
my @seen_state;
my $depth = 1;
foreach my $state (@pending_state) {
$seen_state[$state] = $depth;
}
while (@pending_state) {
my @new_pending_state;
foreach my $state (@pending_state) {
$count++;
### consider state: $state
foreach my $digit (0 .. 3) {
my $next_state = $next_state[$state+$digit];
if (! $seen_state[$next_state]) {
$seen_state[$next_state] = $depth;
push @new_pending_state, $next_state;
### push: "$next_state depth $depth"
}
}
$depth++;
}
@pending_state = @new_pending_state;
}
for (my $state = 0; $state < @next_state; $state += 2) {
$seen_state[$state] ||= '-';
my $state_string = state_string($state);
print "# used state $state depth $seen_state[$state] $state_string\n";
}
print "used state count $count\n";
}
exit 0;
# # lowdigit
# # my @state_to_dx = (1,1,0,0,
# # -1,-1,0,1,
# # -1,0,0,0,
# # 1,0,0,1,
# # );
# # my @state_to_dy = (0,0,1,1,
# # 0,0,-1,0,
# # 0,1,1,1,
# # 0,-1,-1,0,
# # );
#
# my @state_to_dx = (1,1,0,0,
# -1,-1,0,1,
# -1,0,0,0,
# 1,0,0,1,
# );
# my @state_to_dy = (0,0,1,1,
# 0,0,-1,0,
# 0,1,1,1,
# 0,-1,-1,0,
# );
#
# #use Smart::Comments;
#
# sub n_to_dxdy {
# my ($self, $n) = @_;
# ### AlternatePaperMidpoint n_to_dxdy(): $n
#
# if ($n < 0) { return; }
# if (is_infinite($n)) { return ($n, $n); }
#
# my $arm = _divrem_mutate ($n, $self->{'arms'});
# ### $arm
# ### $n
#
# my @digits = digit_split_lowtohigh($n,4);
# while (@digits >= 2 && $digits[0] == 3) { # strip low 3s
# shift @digits;
# }
# my $state = 0;
# my $lowdigit = (shift @digits || 0);
# foreach my $digit (reverse @digits) { # high to low
# $state = $next_state[$state+$digit];
# }
# ### $state
# # ### $lowdigit
# $state += $lowdigit;
# my $dx = $state_to_dx[$state];
# my $dy = $state_to_dy[$state];
#
# if ($arm & 1) {
# ($dx,$dy) = ($dy,$dx); # transpose
# }
# if ($arm & 2) {
# ($dx,$dy) = (-$dy,$dx); # rotate +90
# }
# if ($arm & 4) {
# $dx = - $dx; # rotate 180
# $dy = - $dy;
# }
#
# # ### rotated return: "$dx,$dy"
# return ($dx,$dy);
# }
#
#
# no Smart::Comments;
Math-PlanePath-113/devel/sacks.pl 0000644 0001750 0001750 00000002042 11617621117 014440 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
use warnings;
# uncomment this to run the ### lines
use Smart::Comments;
{
require Math::PlanePath::SacksSpiral;
foreach my $i (0 .. 40) {
my $n;
$n = $i*$i + $i;
$n = $i*$i;
my ($x, $y) = Math::PlanePath::SacksSpiral->n_to_xy($n);
printf "%d %d, %d\n", $i, $x, $y;
}
exit 0;
}
Math-PlanePath-113/devel/c-curve.pl 0000644 0001750 0001750 00000015563 12205252460 014707 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
# uncomment this to run the ### lines
# use Smart::Comments;
{
# A047838 1, 3, 7, 11, 17, 23, 31, 39, 49, 59, 71, 83, 97, 111, 127, 143,
# A080827 1, 3, 5, 9, 13, 19, 25, 33, 41, 51, 61, 73, 85, 99, 113, 129,
require Image::Base::Text;
my $width = 60;
my $height = 30;
my $w2 = int(($width+1)/2);
my $h2 = int($height/2);
my $image = Image::Base::Text->new (-width => $width,
-height => $height);
my $x = $w2;
my $y = $h2;
my $dx = 1;
my $dy = 0;
foreach my $i (2 .. 102) {
$image->xy($x,$y,'*');
if ($dx) {
$x += $dx;
$image->xy($x,$y,'-');
$x += $dx;
$image->xy($x,$y,'-');
$x += $dx;
} else {
$y += $dy;
$image->xy($x,$y,'|');
$y += $dy;
}
my $value = A080827_pred($i);
if (! $value) {
if ($i & 1) {
($dx,$dy) = ($dy,-$dx);
} else {
($dx,$dy) = (-$dy,$dx);
}
}
}
$image->save('/dev/stdout');
exit 0;
}
{
# drawing turn sequence Language::Logo
require Language::Logo;
require Math::NumSeq::OEIS;
# A003982=0,1 characteristic of A001844=2n(n+1)+1
# constant A190406
# my $seq = Math::NumSeq::OEIS->new (anum => 'A003982');
# each leg 4 longer
# 1, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# my $seq = Math::NumSeq::OEIS->new (anum => 'A080827');
require Math::NumSeq::Squares;
my $square = Math::NumSeq::Squares->new;
my @value = (1, 0,
1, 0, 0, 0,
1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
);
# A010052 charact of squares
# 1,
# 1, 0, 0,
# 1, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# A047838
@value = (1, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
);
for (my $i = 0; $i <= $#value; $i++) {
if ($value[$i]) { print $i+1,","; }
}
print "\n";
# exit 0;
my $lo = Logo->new(update => 20, port=>8222+time()%100);
$lo->command("pendown");
$lo->command("seth 0");
foreach my $n (1 .. 2560) {
# my ($i, $value) = $seq->next or last;
# 2n(n+1)+1
# my $i = $n+1;
# my $value = $square->pred(2*$n+1);
# my $i = $n+1;
# my $value = $value[$i-1] // last;
# i = floor(n^2/2)-1.
# i+1 = floor(n^2/2)
# 2i+2 = n^2
my $i = $n+1;
my $value = A080827_pred($i);
$lo->command("forward 10");
if (! $value) {
if ($i & 1) {
$lo->command("left 90");
} else {
$lo->command("right 90");
}
}
}
$lo->disconnect("Finished...");
exit 0;
}
BEGIN {
require Math::NumSeq::OEIS;
# my $seq = Math::NumSeq::OEIS->new (anum => 'A080827');
my $seq = Math::NumSeq::OEIS->new (anum => 'A047838');
my %values;
while (my($i,$value) = $seq->next) {
$values{$value} = 1;
}
sub A080827_pred {
my ($value) = @_;
return $values{$value};
# return $seq->pred($value);
}
}
{
# drawing with Language::Logo
require Language::Logo;
require Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new(planepath=>'DragonCurve',
turn_type => 'Right');
require Math::NumSeq::Fibbinary;
my $fibbinary = Math::NumSeq::Fibbinary->new;
my $lo = Logo->new(update => 20, port=>8222);
$lo->command("pendown");
foreach my $n (1 .. 2560) {
# my $b = $n;
$b = $fibbinary->ith($b);
# my $turn4 = count_low_0_bits($b) - 1;
# my $turn360 = $turn4 * 90;
# $lo->command("forward 3; right $turn360");
my $dir4 = count_1_bits($b) - 1;
my $dir360 = $dir4 * 90;
$lo->command("forward 3; seth $dir360");
}
$lo->disconnect("Finished...");
exit 0;
sub count_1_bits {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += ($n & 1);
$n >>= 1;
}
return $count;
}
sub count_low_0_bits {
my ($n) = @_;
if ($n == 0) { die; }
my $count = 0;
until ($n % 2) {
$count++;
$n /= 2;
}
return $count;
}
}
{
# repeat points
require Math::PlanePath::CCurve;
my $path = Math::PlanePath::CCurve->new;
my %seen;
my @first;
foreach my $n (0 .. 2**16 - 1) {
my ($x, $y) = $path->n_to_xy ($n);
my $xy = "$x,$y";
my $count = ++$seen{$xy};
$first[$count] ||= $xy;
}
### @first
foreach my $xy (@first) {
$xy or next;
my ($x,$y) = split /,/, $xy;
my @n_list = $path->xy_to_n_list($x,$y);
print "$xy N=",join(', ',@n_list),"\n";
}
my @count;
while (my ($key,$visits) = each %seen) {
$count[$visits]++;
if ($visits > 4) {
print "$key $visits\n";
}
}
### @count
exit 0;
}
{
# _rect_to_level()
require Math::PlanePath::CCurve;
foreach my $x (0 .. 16) {
my ($len,$level) = Math::PlanePath::CCurve::_rect_to_level(0,0,$x,0);
$len = $len*$len-1;
print "$x $len $level\n";
}
foreach my $x (0 .. 16) {
my ($len,$level) = Math::PlanePath::CCurve::_rect_to_level(0,0,0,$x);
$len = $len*$len-1;
print "$x $len $level\n";
}
foreach my $x (0 .. 16) {
my ($len,$level) = Math::PlanePath::CCurve::_rect_to_level(0,0,-$x,0);
$len = $len*$len-1;
print "$x $len $level\n";
}
foreach my $x (0 .. 16) {
my ($len,$level) = Math::PlanePath::CCurve::_rect_to_level(0,0,0,-$x);
$len = $len*$len-1;
print "$x $len $level\n";
}
exit 0;
}
Math-PlanePath-113/devel/hilbert.pl 0000644 0001750 0001750 00000033112 12046623475 014775 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.010;
use strict;
use Math::PlanePath::HilbertCurve;
#use Smart::Comments;
{
require Math::NumSeq::PlanePathCoord;
require Math::PlanePath::AR2W2Curve;
foreach my $start_shape (@{Math::PlanePath::AR2W2Curve
->parameter_info_hash->{'start_shape'}->{'choices'}}) {
my $hseq = Math::NumSeq::PlanePathCoord->new (planepath => 'HilbertCurve',
coordinate_type => 'RSquared');
my $aseq = Math::NumSeq::PlanePathCoord->new
(planepath => "AR2W2Curve,start_shape=$start_shape",
coordinate_type => 'RSquared');
foreach my $i ($hseq->i_start .. 10000) {
if ($hseq->ith($i) != $aseq->ith($i)) {
print "$start_shape different at $i\n";
last;
}
}
}
exit 0;
}
{
require Math::PlanePath::ZOrderCurve;
my $hilbert = Math::PlanePath::HilbertCurve->new;
my $zorder = Math::PlanePath::ZOrderCurve->new;
sub zorder_perm {
my ($n) = @_;
my ($x, $y) = $zorder->n_to_xy ($n);
return $hilbert->xy_to_n ($x, $y);
}
sub cycle_length {
my ($n) = @_;
my %seen;
my $count = 1;
my $p = $n;
for (;;) {
$p = zorder_perm($p);
if ($p == $n) {
last;
}
$count++;
}
return $count;
}
foreach my $n (0 .. 128) {
my $perm = zorder_perm($n);
my $len = cycle_length($n);
print "$n $perm $len\n";
}
exit 0;
}
{
require Math::BaseCnv;
require Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new (delta_type => 'Dir4',
planepath => 'HilbertCurve');
foreach my $n (0 .. 256) {
my $n4 = Math::BaseCnv::cnv($n,10,4);
my $want = $seq->ith($n);
my $got = dir_try($n);
my $str = ($want == $got ? '' : ' ***');
printf "%2d %3s %d %d%s\n", $n, $n4, $want, $got, $str;
}
exit 0;
# my @next_state = (4,0,0,12, 0,4,4,8, 12,8,8,4, 8,12,12,0);
# my @digit_to_x = (0,1,1,0, 0,0,1,1, 1,0,0,1, 1,1,0,0);
# my @digit_to_y = (0,0,1,1, 0,1,1,0, 1,1,0,0, 1,0,0,1);
# dx dy dir
# 0 +1 0 0,1,2 4,0,0,12 0=XYswap dir^1 3 y=-x dir^3 low^1 or ^3
# 4 0 +1 1,0,3 0,4,4,8 3 x=-y
# 8 -1 0 2,3,0 12,8,8,4,
# 12 0 -1 3,2,1 8,12,12,0 0=XYswap dir^1
# [012]3333
# [123]0000
# p = count 3s 0 if dx+dy=-1 so dx=-1 or dy=-1 SW, 1 if dx+dy=1 NE
# m = count 3s in -n 0 if dx-dy=-1 NW, 1 if dx-dy=1 SE
# 1023200 neg = 2310133+1 = 2310200 count 0s except trailing 0s
sub dir_try {
my ($n) = @_;
### dir_try(): $n
# p = count 3s 0 if dx+dy=-1 so dx=-1 or dy=-1 SW, 1 if dx+dy=1 NE
# m = count 3s in -n 0 if dx-dy=-1 NW, 1 if dx-dy=1 SE
# 1023200 neg = 2310133+1 = 2310200 count 0s except trailing 0s
$n++;
my $p = count_3s($n) & 1;
my $m = count_3s((-$n) & 0xFF) & 1;
### n : sprintf "%8b", $n
### neg: sprintf "%8b", (-$n) & 0xFF
### $p
### $m
if ($p == 0) {
if ($m == 0) {
return 0; # E
} else {
return 1; # S
}
} else {
if ($m == 0) {
return 3; # N
} else {
return 2; # W
}
}
# my $state = 0;
# my @digits = digits($n);
# if (@digits & 1) {
# # $state ^= 1;
# }
# # unshift @digits, 0;
# ### @digits
#
# my $flip = 0;
# my $dir = 0;
# for (;;) {
# if (! @digits) {
# return $flip;
# }
# $dir = pop @digits;
# if ($dir == 3) {
# $flip ^= 1;
# } else {
# last;
# }
# }
# if ($flip) {
# $dir = 1-$dir;
# }
#
# while (@digits) {
# my $digit = pop @digits;
# ### at: "state=$state digit=$digit dir=$dir"
#
# if ($digit == 0) {
# }
# if ($digit == 1) {
# $dir = 1-$dir;
# }
# if ($digit == 2) {
# $dir = 1-$dir;
# }
# if ($digit == 3) {
# $dir = $dir+2;
# }
# }
#
# ### $dir
# return $dir % 4;
# works ...
#
# while (@digits && $digits[-1] == 3) {
# $state ^= 1;
# pop @digits;
# }
# # if (@digits) {
# # push @digits, $digits[-1];
# # }
#
# while (@digits > 1) {
# my $digit = shift @digits;
# ### at: "state=$state digit=$digit dir=$dir"
#
# if ($digit == 0) {
# }
# if ($digit == 1) {
# $state ^= 1;
# }
# if ($digit == 2) {
# $state ^= 1;
# }
# if ($digit == 3) {
# $state ^= 2;
# }
# }
#
# ### $state
# ### $digit
# my $dir = $digits[0] // return $state^1;
# if ($state & 1) {
# $dir = 1-$dir;
# }
# if ($state & 2) {
# $dir = $dir+2;
# }
# ### $dir
#
#
# ### $dir
# return $dir % 4;
# my $digit = $digits[-1];
# if ($digit == 0) {
# $dir = 0;
# }
# if ($digit == 1) {
# $dir = 2;
# }
# if ($digit == 2) {
# $dir = 1;
# }
# if ($digit == 3) {
# $dir = 1;
# }
# if (@digits & 1) {
# $dir = 1-$dir;
# }
# my $ret = $dir;
#
# while (@digits) {
# my $digit = shift @digits;
# if ($digit == 0) {
# $dir = 1-$dir;
# $ret = $dir;
# }
# if ($digit == 1) {
# $ret = $dir;
# }
# if ($digit == 2) {
# $ret = $dir;
# }
# if ($digit == 3) {
# $dir = $dir + 2;
# }
# }
# return $ret % 4;
# $ret = 0;
# while (($n & 3) == 3) {
# $n >>= 2;
# $ret ^= 1;
# }
#
# my $digit = ($n & 3);
# $n >>= 2;
# if ($digit == 0) {
# }
# if ($digit == 1) {
# $ret++;
# }
# if ($digit == 2) {
# $ret += 2;
# }
# if ($digit == 3) {
# }
#
# while ($n) {
# my $digit = ($n & 3);
# $n >>= 2;
#
# if ($digit == 0) {
# $ret = 1-$ret;
# }
# if ($digit == 1) {
# $ret = -$ret;
# # $ret = 1-$ret;
# }
# if ($digit == 2) {
# $ret = 1-$ret;
# }
# if ($digit == 3) {
# $ret = $ret + 2;
# }
# }
# return $ret % 4;
#
#
#
# if (($n & 3) == 3) {
# while (($n & 15) == 15) {
# $n >>= 4;
# }
# if (($n & 3) == 3) {
# $ret = 1;
# }
# $n >>= 2;
# } elsif (($n & 3) == 1) {
# $ret = 0;
# $n >>= 2;
# } elsif (($n & 3) == 2) {
# $ret = 2;
# $n >>= 2;
# }
#
# while ($n) {
# if (($n & 3) == 0) {
# $ret ^= 1;
# }
# if (($n & 3) == 3) {
# $ret ^= 2;
# }
# $n >>= 2;
# }
# return $ret;
}
sub digits {
my ($n) = @_;
my @ret;
while ($n) {
unshift @ret, $n & 3;
$n >>= 2;
} ; # || @ret&1
return @ret;
}
sub count_3s {
my ($n) = @_;
my $count = 0;
while ($n) {
$count += (($n & 3) == 3);
$n >>= 2;
$count += (($n & 3) == 3);
$n >>= 2;
}
return $count;
}
}
{
my $path = Math::PlanePath::HilbertCurve->new;
my @range = $path->rect_to_n_range (1,2, 2,4);
### @range
exit 0;
}
{
my $path = Math::PlanePath::HilbertCurve->new;
sub want {
my ($n) = @_;
my ($x1,$y1) = $path->n_to_xy($n);
my ($x2,$y2) = $path->n_to_xy($n+1);
return ($x2-$x1, $y2-$y1);
}
sub try {
my ($n) = @_;
### try(): $n
while (($n & 15) == 15) {
$n >>= 4;
}
my $pos = 0;
my $mask = 16;
while ($n >= $mask) {
$pos += 4;
$mask <<= 4;
}
### $pos
my $dx = 1;
my $dy = 0;
### d initial: "$dx,$dy"
while ($pos >= 0) {
my $bits = ($n >> $pos) & 15;
### $bits
if ($bits == 1
|| $bits == 2
|| $bits == 3
|| $bits == 4
|| $bits == 8
) {
($dx,$dy) = ($dy,$dx);
### d swap to: "$dx,$dy"
} elsif ($bits == 2
|| $bits == 12
) {
$dx = -$dx;
$dy = -$dy;
### d invert: "$dx,$dy"
} elsif ($bits == 2
|| $bits == 10
|| $bits == 11
|| $bits == 13
) {
($dx,$dy) = ($dy,$dx);
$dx = -$dx;
$dy = -$dy;
### d swap and invert: "$dx,$dy"
} elsif ($bits == 0
|| $bits == 5
) {
### d unchanged
}
$pos -= 4;
}
return ($dx,$dy);
}
sub Wtry {
my ($n) = @_;
### try(): $n
my $pos = 0;
my $mask = 16;
while ($n >= $mask) {
$pos += 4;
$mask <<= 4;
}
### $pos
my $dx = 1;
my $dy = 0;
### d initial: "$dx,$dy"
while ($pos >= 0) {
my $bits = ($n >> $pos) & 15;
### $bits
if ($bits == 1
|| $bits == 3
|| $bits == 4
|| $bits == 8
) {
($dx,$dy) = ($dy,$dx);
### d swap to: "$dx,$dy"
} elsif ($bits == 2
|| $bits == 12
) {
$dx = -$dx;
$dy = -$dy;
### d invert: "$dx,$dy"
} elsif ($bits == 2
|| $bits == 6
|| $bits == 10
|| $bits == 11
|| $bits == 13
) {
($dx,$dy) = ($dy,$dx);
$dx = -$dx;
$dy = -$dy;
### d swap and invert: "$dx,$dy"
} elsif ($bits == 0
|| $bits == 5
) {
### d unchanged
}
$pos -= 4;
}
return ($dx,$dy);
}
sub ZZtry {
my ($n) = @_;
my $dx = 0;
my $dy = 1;
do {
my $bits = $n & 3;
if ($bits == 0) {
($dx,$dy) = ($dy,$dx);
### d swap: "$dx,$dy"
} elsif ($bits == 1) {
# ($dx,$dy) = ($dy,$dx);
# ### d swap: "$dx,$dy"
} elsif ($bits == 2) {
($dx,$dy) = ($dy,$dx);
### d swap: "$dx,$dy"
$dx = -$dx;
$dy = -$dy;
### d invert: "$dx,$dy"
} elsif ($bits == 3) {
### d unchanged
}
my $prevbits = $bits;
$n >>= 2;
return ($dx,$dy) if ! $n;
$bits = $n & 3;
if ($bits == 0) {
### d unchanged
} elsif ($bits == 1) {
($dx,$dy) = ($dy,$dx);
### d swap: "$dx,$dy"
} elsif ($bits == 2) {
if ($prevbits >= 2) {
}
# $dx = -$dx;
# $dy = -$dy;
($dx,$dy) = ($dy,$dx);
### d swap: "$dx,$dy"
} elsif ($bits == 3) {
($dx,$dy) = ($dy,$dx);
### d invert and swap: "$dx,$dy"
}
$n >>= 2;
} while ($n);
return ($dx,$dy);
}
my @n_to_next_i = (4, 0, 0, 8, # i=0
0, 4, 4, 12, # i=4
12, 8, 8, 0, # i=8
8, 12, 12, 4, # i=12
);
my @n_to_x = (0, 1, 1, 0, # i=0
0, 0, 1, 1, # i=4
1, 1, 0, 0, # i=8
1, 0, 0, 1, # i=12
);
my @n_to_y = (0, 0, 1, 1, # i=0
0, 1, 1, 0, # i=4
1, 0, 0, 1, # i=8
1, 1, 0, 0, # i=12
);
my @i_to_dx = (1, 0, -1, 3, 0, 1, 0, 7,-1, 1, 10, 0,-1, 0,1,15);
my @i_to_dy = (0, 1, 0, 3, 1, 0, -1, 7, 0, 0, 10, 1, 0,-1,0,15);
# unswapped
# my @i_to_dx = (1, 0, -1, 3, 0, 1, 0, 7,-1, 1, 10, 0,-1, 0,1,15);
# my @i_to_dy = (0, 1, 0, 3, 1, 0, -1, 7, 0, 0, 10, 1, 0,-1,0,15);
# my @i_to_dx = (0 .. 15);
# my @i_to_dy = (0 .. 15);
sub Xtry {
my ($n) = @_;
### HilbertCurve n_to_xy(): $n
### hex: sprintf "%#X", $n
return if $n < 0;
my $x = my $y = ($n * 0); # inherit
my $pos = 0;
{
my $pow = $x + 4; # inherit
while ($n >= $pow) {
$pow <<= 2;
$pos += 2;
}
}
### $pos
my $dx = 9;
my $dy = 9;
my $i = ($pos & 2) << 1;
my $t;
while ($pos >= 0) {
my $nbits = (($n >> $pos) & 3);
$t = $i + $nbits;
$x = ($x << 1) | $n_to_x[$t];
$y = ($y << 1) | $n_to_y[$t];
### $pos
### $i
### bits: ($n >> $pos) & 3
### $t
### n_to_x: $n_to_x[$t]
### n_to_y: $n_to_y[$t]
### next_i: $n_to_next_i[$t]
### x: sprintf "%#X", $x
### y: sprintf "%#X", $y
# if ($nbits == 0) {
# } els
if ($nbits == 3) {
if ($pos & 2) {
($dx,$dy) = ($dy,$dx);
}
} else {
($dx,$dy) = ($i_to_dx[$t], $i_to_dy[$t]);
}
$i = $n_to_next_i[$t];
$pos -= 2;
}
print "final i $i\n";
return ($dx,$dy);
}
sub base4 {
my ($n) = @_;
my $ret = '';
do {
$ret .= ($n & 3);
} while ($n >>= 2);
return reverse $ret;
}
foreach my $n (0 .. 256) {
my $n4 = base4($n);
my ($wdx,$wdy) = want($n);
my ($tdx,$tdy) = try($n);
my $diff = ($wdx!=$tdx || $wdy!=$tdy ? " ***" : "");
print "$n $n4 $wdx,$wdy $tdx,$tdy $diff\n";
}
exit 0;
# p=dx+dy +/-1
# m=dx-dy +/-1
#
# p = count 3s in N, odd/even
# m = count 3s in -N, odd/even
#
# p==m is dx
# p!=m then p is dy
}
Math-PlanePath-113/devel/quintet-replicate.pl 0000644 0001750 0001750 00000006104 12003406621 016765 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
use Math::Libm 'M_PI', 'hypot';
{
# Dir4 maximum
require Math::PlanePath::QuintetReplicate;
require Math::NumSeq::PlanePathDelta;
require Math::BigInt;
require Math::BaseCnv;
my $path = Math::PlanePath::QuintetReplicate->new;
my $seq = Math::NumSeq::PlanePathDelta->new (planepath_object => $path,
delta_type => 'Dir4');
my $dir4_max = 0;
foreach my $n (0 .. 600000) {
# my $n = Math::BigInt->new(2)**$level - 1;
my $dir4 = $seq->ith($n);
if ($dir4 > $dir4_max) {
$dir4_max = $dir4;
my ($dx,$dy) = $path->n_to_dxdy($n);
my $n5 = Math::BaseCnv::cnv($n,10,5);
printf "%7s %2b,\n %2b %8.6f\n", $n5, abs($dx),abs($dy), $dir4;
}
}
exit 0;
}
{
# min/max for level
require Math::BaseCnv;
require Math::PlanePath::QuintetReplicate;
my $path = Math::PlanePath::QuintetReplicate->new;
my $prev_min = 1;
my $prev_max = 1;
my @mins;
for (my $level = 0; $level < 20; $level++) {
my $n_start = 5**$level;
my $n_end = 5**($level+1) - 1;
my $min_hypot = 128*$n_end*$n_end;
my $min_x = 0;
my $min_y = 0;
my $min_pos = '';
my $max_hypot = 0;
my $max_x = 0;
my $max_y = 0;
my $max_pos = '';
print "level $level n=$n_start .. $n_end\n";
foreach my $n ($n_start .. $n_end) {
my ($x,$y) = $path->n_to_xy($n);
my $h = $x*$x + $y*$y;
# my $h = abs($x) + abs($y);
if ($h < $min_hypot) {
my $n5 = Math::BaseCnv::cnv($n,10,5) . '[5]';
$min_hypot = $h;
$min_pos = "$x,$y $n $n5";
}
if ($h > $max_hypot) {
my $n5 = Math::BaseCnv::cnv($n,10,5) . '[5]';
$max_hypot = $h;
$max_pos = "$x,$y $n $n5";
}
}
# print " min $min_hypot at $min_x,$min_y\n";
# print " max $max_hypot at $max_x,$max_y\n";
{
my $factor = $min_hypot / $prev_min;
my $base5 = Math::BaseCnv::cnv($min_hypot,10,5) . '[5]';
print " min $min_hypot $base5 at $min_pos factor $factor\n";
}
# {
# my $factor = $max_hypot / $prev_max;
# my $base5 = Math::BaseCnv::cnv($max_hypot,10,5) . '[5]';
# print " max $max_hypot $base5 at $max_pos factor $factor\n";
# }
$prev_min = $min_hypot;
$prev_max = $max_hypot;
push @mins, $min_hypot;
}
print join(',',@mins),"\n";
exit 0;
}
Math-PlanePath-113/devel/iterator.pl 0000644 0001750 0001750 00000017047 11604443335 015200 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.006;
use strict;
use warnings;
=over
=item C<($n, $x, $y) = $path-Enext()>
=item C<($n, $x, $y) = $path-Enext_nxy()>
=item C<($n, $x, $y) = $path-Epeek()>
=item C<$path-Erewind()>
=item C<$path-Eseek_to_n($n)>
=item C<$n = $path-Etell_n($n)>
=item C<($n,$x,$y) = $path-Etell_nxy($n)>
=back
=cut
use Math::PlanePath;
{
package Math::PlanePath;
no warnings 'redefine';
sub new {
my $class = shift;
my $self = bless { @_ }, $class;
$self->rewind;
return $self;
}
sub rewind {
my ($self) = @_;
$self->seek_to_n($self->n_start);
}
sub seek_to_n {
my ($self, $n) = @_;
$self->{'n'} = $n;
}
sub tell_n {
my ($self, $n) = @_;
return $self->{'n'};
}
sub next_nxy {
my ($self) = @_;
my $n = $self->{'n'}++;
return ($n, $self->n_to_xy($n));
}
sub peek_nxy {
my ($self) = @_;
my $n = $self->{'n'};
return ($n, $self->n_to_xy($n));
}
}
{
use Math::PlanePath::ZOrderCurve;
package Math::PlanePath::ZOrderCurve;
# sub seek_to_n {
# my ($self, $n) = @_;
# ($self->{'x'},$self->{'y'}) = $self->n_to_xy($self->{'n'} = $n);
# $self->{'bx'} = $x;
# $self->{'by'} = $y;
# $self->{'a'} = [ \$self->{'x'}, \$self->{'y'} ];
# $self->{'i'} = 1;
# ### ZOrderCurve seek_to_n(): $self
# }
# sub next_nxy {
# my ($self) = @_;
# $self->{'a'}->[($self->{'i'} ^= 1)]++;
# return (++$self->{'n'}, $self->{'x'}, $self->{'y'});
# }
# sub peek_nxy {
# my ($self) = @_;
# return ($self->{'n'} + 1,
# $self->{'x'} + !$self->{'i'},
# $self->{'y'} + $self->{'i'});
# }
}
{
use Math::PlanePath::Rows;
package Math::PlanePath::Rows;
sub seek_to_n {
my ($self, $n) = @_;
$self->{'n'} = --$n;
my $width = $self->{'width'};
$self->{'px'} = ($n % $width) - 1;
$self->{'py'} = int ($n / $width);
### seek_to_n: $self
}
sub next_nxy {
my ($self) = @_;
my $x = ++$self->{'px'};
if ($x >= $self->{'width'}) {
$x = $self->{'px'} = 0;
$self->{'py'}++;
}
return (++$self->{'n'}, $x, $self->{'py'});
}
sub peek_nxy {
my ($self) = @_;
if ((my $x = $self->{'px'} + 1) < $self->{'width'}) {
return ($self->{'n'}+1, $x, $self->{'py'});
} else {
return ($self->{'n'}+1, 0, $self->{'py'}+1);
}
}
}
{
use Math::PlanePath::Diagonals;
package Math::PlanePath::Diagonals;
# N = (1/2 d^2 + 1/2 d + 1)
# = (1/2*$d**2 + 1/2*$d + 1)
# = ((0.5*$d + 0.5)*$d + 1)
# d = -1/2 + sqrt(2 * $n + -7/4)
sub seek_to_n {
my ($self, $n) = @_;
$self->{'n'} = $n;
my $d = $self->{'d'} = int (-.5 + sqrt(2*$n - 1.75));
$n -= $d*($d+1)/2 + 1;
$self->{'px'} = $n - 1;
$self->{'py'} = $d - $n + 1;
### Diagonals seek_to_n(): $self
}
sub next_nxy {
my ($self) = @_;
my $x = ++$self->{'px'};
my $y = --$self->{'py'};
if ($y < 0) {
$x = $self->{'px'} = 0;
$y = $self->{'py'} = ++$self->{'d'};
}
return ($self->{'n'}++, $x, $y);
}
sub peek_nxy {
my ($self) = @_;
if (my $y = $self->{'py'}) {
return ($self->{'n'}, $self->{'px'}+1, $y-1);
} else {
return ($self->{'n'}, 0, $self->{'d'}+1);
}
}
}
{
use Math::PlanePath::SquareSpiral;
package Math::PlanePath::SquareSpiral;
sub next_nxy {
my ($self) = @_;
### next(): $self
my $x = ($self->{'x'} += $self->{'dx'});
my $y = ($self->{'y'} += $self->{'dy'});
unless ($self->{'side'}--) {
### turn
($self->{'dx'},$self->{'dy'}) = (-$self->{'dy'},$self->{'dx'}); # left
$self->{'side'} = (($self->{'d'} += ($self->{'grow'} ^= 1)) - 1)
+ ($self->{'dx'} && $self->{'wider'});
### grow applied: $self->{'grow'}
### d now: $self->{'d'}
### side now: $self->{'side'}
### dx,dy now: "$self->{'dx'},$self->{'dy'}"
}
### return: 'n='.$self->{'n'}.' '.($self->{'x'} + $self->{'dx'}).','.($self->{'y'} + $self->{'dy'})
return ($self->{'n'}++, $x, $y);
}
sub peek_nxy {
my ($self) = @_;
# ### peek(): $self
return ($self->{'n'},
$self->{'x'} + $self->{'dx'},
$self->{'y'} + $self->{'dy'});
}
# N = (1/2 d^2 + 1/2 d + 1)
# = (1/2*$d**2 + 1/2*$d + 1)
# = ((0.5*$d + 0.5)*$d + 1)
# d = -1/2 + sqrt(2 * $n + -7/4)
sub seek_to_n {
my ($self, $n) = @_;
### SquareSpiral seek_to_n: $n
$self->{'n'} = $n;
my $d = $self->{'d'} = int (1/2 + sqrt(1 * $n + -3/4));
$n -= (($d - 1)*$d + 1);
### $d
### half d: int($d/2)
### remainder: $n
my $dx;
my $dy;
my $y = - int($d/2);
my $x = $y + $n;
if ($self->{'grow'} = ($n < $d)) {
### horizontal
$dx = 1;
$dy = 0;
} else {
### vertical
$n -= $d;
$dx = 0;
$dy = 1;
($x, $y) = ($y + $d,
$x - $d);
}
if ($d & 1) {
} else {
### negate for even d from: "$x,$y"
$dx = - $dx;
$dy = - $dy;
$x = -$x;
$y = -$y;
}
$self->{'side'} = $d - $n;
$self->{'dx'} = $dx;
$self->{'dy'} = $dy;
$self->{'x'} = $x - $dx;
$self->{'y'} = $y - $dy;
# if ($n == 3) {
# $self->{'side'} = 2;
# $self->{'grow'} = 1;
# $self->{'d'} = 2;
# $self->{'dx'} = -1;
# $self->{'dy'} = 0;
# $self->{'x'} = 2;
# $self->{'y'} = 1;
# return;
# }
#
# $self->{'n'} = $n;
# $self->{'side'} = 1;
# $self->{'grow'} = 0;
# $self->{'d'} = 0;
# $self->{'dx'} = 1;
# $self->{'dy'} = 0;
# $self->{'x'} = -1;
# $self->{'y'} = 0;
### SquareSpiral seek_to_n(): $self
}
}
use Smart::Comments;
foreach my $class ('Math::PlanePath::SquareSpiral',
'Math::PlanePath::Diagonals',
'Math::PlanePath::Rows',
) {
my $path = $class->new (width => 5);
foreach my $n_start_offset (0 .. 30) {
my $want_n = $path->n_start;
if ($n_start_offset) {
$want_n += $n_start_offset;
$path->seek_to_n ($want_n);
}
### $class
### $n_start_offset
foreach my $i (0 .. 100) {
my ($peek_n, $peek_x, $peek_y) = $path->peek;
my ($got_n, $got_x, $got_y) = $path->next;
my ($want_x, $want_y) = $path->n_to_xy($want_n);
if ($want_n != $got_n) {
### $want_n
### $got_n
die "x";
}
if ($want_x != $got_x) {
### $want_n
### $want_x
### $got_x
die "x";
}
if ($want_y != $got_y) {
### $want_n
### $want_y
### $got_y
die "x";
}
if ($peek_n != $want_n) {
### $peek_n
### $want_n
die "x";
}
if ($peek_x != $want_x) {
### $want_n
### $peek_x
### $want_x
die "x";
}
if ($peek_y != $want_y) {
### $want_n
### $peek_y
### $want_y
die "x";
}
$want_n++;
}
}
}
Math-PlanePath-113/devel/divisible-columns.pl 0000644 0001750 0001750 00000002456 11775424704 017005 0 ustar gg gg #!/usr/bin/perl -w
# Copyright 2010, 2011, 2012 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
use 5.004;
use strict;
{
require Math::PlanePath::DivisibleColumns;
my $path = Math::PlanePath::DivisibleColumns->new;
$path->xy_to_n(2000,2000);
foreach my $k (3 .. 1000) {
# my $total = 0;
# my $limit = int(sqrt($k));
# foreach my $i (1 .. $limit) {
# $total += int($k/$i);
# }
# $total = 2*$total - $limit*$limit;
my $n = $path->xy_to_n($k,$k);
my (undef, $nhi) = $path->rect_to_n_range(0,0,$k,$k);
my $total = Math::PlanePath::DivisibleColumns::_count_divisors_cumulative($k);
printf "%d %d,%d %d\n", $k, $n,$nhi, $total;
}
exit 0;
}
Math-PlanePath-113/devel/exe-complex-revolving.c 0000644 0001750 0001750 00000005545 11701165116 017411 0 ustar gg gg /* Copyright 2012 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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 Math-PlanePath. If not, see .
*/
#include
#include
#include
#include
typedef unsigned long my_unsigned;
typedef long long my_signed;
#define MY_SIGNED_ABS llabs
#define HYPOT_LIMIT 0x7FFFFFFF
char *
binary (unsigned long long n)
{
static char str[sizeof(n)*8+1];
int pos = sizeof(str)-1;
do {
str[pos] = (n&1)+'0';
n >>= 1;
pos--;
} while (n);
return str+pos+1;
}
int
main (void)
{
int level;
for (level = 0; level < 8*sizeof(my_unsigned)-1; level++) {
unsigned long long min_h = ~0ULL;
my_unsigned min_n = 0;
my_signed min_x = 0;
my_signed min_y = 0;
{
my_unsigned lo = (my_unsigned)1 << level;
my_unsigned hi = (my_unsigned)1 << (level+1);
/* printf ("%2d lo=%lu hi=%lu\n", level, lo, hi); */
my_unsigned n;
for (n = lo; n < hi; n++) {
my_signed x = 0;
my_signed y = 0;
my_signed bx = 1;
my_signed by = 0;
my_unsigned bits;
for (bits = n; bits != 0; bits >>= 1) {
if (bits & 1) {
x += bx;
y += by;
/* (bx,by) * i, rotate +90 */
my_signed new_bx = -by;
my_signed new_by = bx;
bx = new_bx;
by = new_by;
}
/* (bx,by) * (i+1) */
my_signed new_bx = bx-by;
my_signed new_by = bx+by;
bx = new_bx;
by = new_by;
}
unsigned long long abs_x = MY_SIGNED_ABS(x);
unsigned long long abs_y = MY_SIGNED_ABS(y);
if (abs_x > HYPOT_LIMIT
|| abs_y > HYPOT_LIMIT) {
continue;
}
unsigned long long h = abs_x*abs_x + abs_y*abs_y;
/* printf ("%2d %lu %Ld,%Ld %LX\n", level, n, x,y, h); */
if (h < min_h) {
min_h = h;
min_n = n;
min_x = abs_x;
min_y = abs_y;
}
}
}
/* printf ("%lX %Ld,%Ld %s\n", min_n, min_x,min_y, */
/* binary(min_h)); */
printf ("%2d", level);
char *binary_str = binary(min_h);
int binary_len = strlen(binary_str);
printf (" %s [%d]", binary(min_h), binary_len);
printf ("\n");
/* printf ("\n"); */
}
return 0;
}
Math-PlanePath-113/lib/ 0002755 0001750 0001750 00000000000 12255673732 012463 5 ustar gg gg Math-PlanePath-113/lib/Math/ 0002755 0001750 0001750 00000000000 12255673733 013355 5 ustar gg gg Math-PlanePath-113/lib/Math/NumSeq/ 0002755 0001750 0001750 00000000000 12255673733 014565 5 ustar gg gg Math-PlanePath-113/lib/Math/NumSeq/PlanePathDelta.pm 0000644 0001750 0001750 00000403032 12250720133 017727 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# maybe:
#
# dRadius, dRSquared,
# dTRadius, dTRSquared of the radii
# dTheta360
# 'Dir360','TDir360',
# matching Dir4,TDir6
# dLength
# dDist dDSquared
# dTDist dTDSquared
# Dist DSquared
# TDist TDSquared
# StepDist StepSquared
# StepTDist StepTSquared
# StepRadius
# StepRSquared
package Math::NumSeq::PlanePathDelta;
use 5.004;
use strict;
use Carp;
use List::Util 'max';
use vars '$VERSION','@ISA';
$VERSION = 113;
use Math::NumSeq;
use Math::NumSeq::Base::IterateIth;
@ISA = ('Math::NumSeq::Base::IterateIth',
'Math::NumSeq');
use Math::NumSeq::PlanePathCoord;
*_planepath_name_to_object = \&Math::NumSeq::PlanePathCoord::_planepath_name_to_object;
# uncomment this to run the ### lines
# use Smart::Comments;
use constant 1.02; # various underscore constants below
use constant characteristic_smaller => 1;
sub description {
my ($self) = @_;
if (ref $self) {
return "Coordinate change $self->{'delta_type'} on path $self->{'planepath'}";
} else {
# class method
return 'Coordinate changes from a PlanePath';
}
}
use constant::defer parameter_info_array =>
sub {
[ Math::NumSeq::PlanePathCoord::_parameter_info_planepath(),
{
name => 'delta_type',
display => 'Delta Type',
type => 'enum',
default => 'dX',
choices => ['dX','dY',
'AbsdX','AbsdY',
'dSum','dSumAbs',
'dDiffXY','dDiffYX','dAbsDiff',
'Dir4','TDir6',
'dRadius',
'dRSquared',
# 'Dist','DSquared',
# 'TDist','TDSquared',
],
description => 'Coordinate change or direction to take from the path.',
},
];
};
#------------------------------------------------------------------------------
sub oeis_anum {
my ($self) = @_;
### PlanePathCoord oeis_anum() ...
my $planepath_object = $self->{'planepath_object'};
my $delta_type = $self->{'delta_type'};
{
my $key = Math::NumSeq::PlanePathCoord::_planepath_oeis_anum_key($self->{'planepath_object'});
my $i_start = $self->i_start;
if ($i_start != $self->default_i_start) {
### $i_start
### cf n_start: $planepath_object->n_start
$key .= ",i_start=$i_start";
}
### planepath: ref $planepath_object
### $key
### whole table: $planepath_object->_NumSeq_Delta_oeis_anum
### key href: $planepath_object->_NumSeq_Delta_oeis_anum->{$key}
if (my $anum = $planepath_object->_NumSeq_Delta_oeis_anum->{$key}->{$delta_type}) {
return $anum;
}
}
return undef;
}
#------------------------------------------------------------------------------
sub new {
### NumSeq-PlanePathDelta new(): @_
my $self = shift->SUPER::new(@_);
$self->{'planepath_object'}
||= _planepath_name_to_object($self->{'planepath'});
{
my $delta_type = $self->{'delta_type'};
($self->{'delta_func'} = $self->can("_delta_func_$delta_type"))
or ($self->{'n_func'} = $self->can("_n_func_$delta_type"))
or croak "Unrecognised delta_type: ",$delta_type;
}
$self->rewind;
return $self;
}
sub default_i_start {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'}
# nasty hack allow no 'planepath_object' when SUPER::new() calls rewind()
|| return 0;
return $planepath_object->n_start;
}
sub i_start {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'} || return 0;
return $planepath_object->n_start;
}
# Old code keeping a previous X,Y to take a delta from.
#
# sub rewind {
# my ($self) = @_;
#
# my $planepath_object = $self->{'planepath_object'} || return;
# $self->{'i'} = $self->i_start;
# undef $self->{'x'};
# $self->{'arms_count'} = $planepath_object->arms_count;
# }
# sub next {
# my ($self) = @_;
# ### NumSeq-PlanePathDelta next(): $self->{'i'}
# ### n_next: $self->{'n_next'}
#
# my $planepath_object = $self->{'planepath_object'};
# my $i = $self->{'i'}++;
# my $x = $self->{'x'};
# my $y;
# if (defined $x) {
# $y = $self->{'y'};
# } else {
# ($x, $y) = $planepath_object->n_to_xy ($i)
# or return;
# }
#
# my $arms = $self->{'arms_count'};
# my ($next_x, $next_y) = $planepath_object->n_to_xy($i + $arms)
# or return;
# my $value = &{$self->{'delta_func'}}($x,$y, $next_x,$next_y);
#
# if ($arms == 1) {
# $self->{'x'} = $next_x;
# $self->{'y'} = $next_y;
# }
# return ($i, $value);
# }
sub ith {
my ($self, $i) = @_;
### NumSeq-PlanePathDelta ith(): $i
my $planepath_object = $self->{'planepath_object'};
if (my $func = $self->{'n_func'}) {
return &$func($planepath_object,$i);
}
if (my ($dx, $dy) = $planepath_object->n_to_dxdy($i)) {
return &{$self->{'delta_func'}}($dx,$dy);
}
return undef;
}
sub _delta_func_dX {
my ($dx,$dy) = @_;
return $dx;
}
sub _delta_func_dY {
my ($dx,$dy) = @_;
return $dy;
}
sub _delta_func_AbsdX {
my ($dx,$dy) = @_;
return abs($dx);
}
sub _delta_func_AbsdY {
my ($dx,$dy) = @_;
return abs($dy);
}
sub _delta_func_dSum {
my ($dx,$dy) = @_;
return $dx+$dy;
}
sub _delta_func_dDiffXY {
my ($dx,$dy) = @_;
return $dx-$dy;
}
sub _delta_func_dDiffYX {
my ($dx,$dy) = @_;
return $dy-$dx;
}
# (abs(x2)+abs(y2)) - (abs(x1)+abs(y1))
# = abs(x2)-abs(x1) + abs(y2)-+abs(y1)
# = dAbsX + dAbsY
sub _n_func_dSumAbs {
my ($path, $n) = @_;
### _n_func_dSumAbs(): $n
my ($x1,$y1) = $path->n_to_xy($n)
or return undef;
my ($x2,$y2) = $path->n_to_xy($n + $path->arms_count)
or return undef;
### coords: "x1=$x1 y1=$y1 x2=$x2 y2=$y2"
### result: (abs($x2)+abs($y2)) - (abs($x1)+abs($y1))
return (abs($x2)+abs($y2)) - (abs($x1)+abs($y1));
}
# abs(x2-y2) - abs(x1-y1)
sub _n_func_dAbsDiff {
my ($path, $n) = @_;
my ($x1,$y1) = $path->n_to_xy($n)
or return undef;
my ($x2,$y2) = $path->n_to_xy($n + $path->arms_count)
or return undef;
return abs($x2-$y2) - abs($x1-$y1);
}
sub _n_func_dRadius {
my ($path, $n) = @_;
if (defined (my $r1 = $path->n_to_radius($n))) {
if (defined (my $r2 = $path->n_to_radius($n + $path->arms_count))) {
return ($r2 - $r1);
}
}
return undef;
}
sub _n_func_dRSquared {
my ($path, $n) = @_;
# dRSquared = (x2^2+y2^2) - (x1^2+y1^2)
if (defined (my $r1 = $path->n_to_rsquared($n))) {
if (defined (my $r2 = $path->n_to_rsquared($n + $path->arms_count))) {
return ($r2 - $r1);
}
}
return undef;
}
sub _delta_func_Dist {
return sqrt(_delta_func_DSquared(@_));
}
sub _delta_func_DSquared {
my ($dx,$dy) = @_;
return $dx*$dx + $dy*$dy;
}
sub _delta_func_TDist {
return sqrt(_delta_func_TDSquared(@_));
}
sub _delta_func_TDSquared {
my ($dx,$dy) = @_;
return $dx*$dx + 3*$dy*$dy;
}
sub _delta_func_Dir4 {
my ($dx,$dy) = @_;
### _delta_func_Dir4(): "$dx,$dy"
### 360 is: _delta_func_Dir360($dx,$dy)
return _delta_func_Dir360($dx,$dy) / 90;
}
sub _delta_func_TDir6 {
my ($dx,$dy) = @_;
### _delta_func_TDir6(): "$dx,$dy"
return _delta_func_TDir360($dx,$dy) / 60;
}
sub _delta_func_Dir8 {
my ($dx,$dy) = @_;
return _delta_func_Dir360($dx,$dy) / 45;
}
use constant 1.02; # for leading underscore
use constant _PI => 2*atan2(1,0);
sub _delta_func_Dir360 {
my ($dx,$dy) = @_;
### _delta_func_Dir360(): "$dx,$dy"
if ($dy == 0) {
### dy=0 ...
return ($dx >= 0 ? 0 : 180);
}
if ($dx == 0) {
### dx=0 ...
return ($dy > 0 ? 90 : 270);
}
if ($dx > 0) {
if ($dx == $dy) { return 45; }
if ($dx == -$dy) { return 315; }
} else {
if ($dx == $dy) { return 225; }
if ($dx == -$dy) { return 135; }
}
my $radians_to_degrees;
# don't atan2() on BigInt, go to BigFloat
foreach ($dx, $dy) {
if (ref $_ && ($_->isa('Math::BigInt') || $_->isa('Math::BigRat'))) {
require Math::BigFloat;
$_ = Math::BigFloat->new($_);
# 180/pi with pi done in BigFloat configured precision
$radians_to_degrees ||= do {
require Math::PlanePath::MultipleRings;
180 / Math::PlanePath::MultipleRings::_pi($_);
};
}
}
$radians_to_degrees ||= 180 / _PI;
### $radians_to_degrees
### $dx
### $dy
### atan2: atan2($dy,$dx)
# atan2() returns -PI <= a <= PI and perlfunc says atan2(0,0) is "not well
# defined" (though glibc gives 0). Add 360 to negatives to give 0<=dir<360.
#
my $degrees = atan2($dy,$dx) * $radians_to_degrees;
### $degrees
return ($degrees < 0 ? $degrees + 360 : $degrees);
}
sub _delta_func_TDir360 {
my ($dx,$dy) = @_;
### _delta_func_TDir360(): "$dx,$dy"
if ($dy == 0) {
return ($dx >= 0 ? 0 : 180);
}
if ($dx == 0) {
return ($dy > 0 ? 90 : 270);
}
if ($dx > 0) {
if ($dx == 3*$dy) { return 30; }
if ($dx == $dy) { return 60; }
if ($dx == -$dy) { return 300; }
if ($dx == -3*$dy) { return 330; }
} else {
if ($dx == -$dy) { return 120; }
if ($dx == -3*$dy) { return 150; }
if ($dx == 3*$dy) { return 210; }
if ($dx == $dy) { return 240; }
}
# Crib: atan2() returns -PI <= a <= PI, and is supposedly "not well
# defined", though glibc gives 0
#
my $degrees = atan2($dy*sqrt(3), $dx) * (180 / _PI);
return ($degrees < 0 ? $degrees + 360 : $degrees);
}
#------------------------------------------------------------------------------
sub characteristic_integer {
my ($self) = @_;
my $method = "_NumSeq_Delta_$self->{'delta_type'}_integer";
return $self->{'planepath_object'}->$method();
}
sub characteristic_increasing {
my ($self) = @_;
### PlanePathDelta characteristic_increasing() ...
my $planepath_object = $self->{'planepath_object'};
my $func;
return
(($func = ($planepath_object->can("_NumSeq_Delta_$self->{'delta_type'}_increasing")
|| ($self->{'delta_type'} eq 'DSquared'
&& $planepath_object->can("_NumSeq_Delta_Dist_increasing"))
|| ($self->{'delta_type'} eq 'TDSquared'
&& $planepath_object->can("_NumSeq_Delta_TDist_increasing"))))
? $planepath_object->$func()
: undef); # unknown
}
sub characteristic_non_decreasing {
my ($self) = @_;
### PlanePathDelta characteristic_non_decreasing() ...
if (defined (my $values_min = $self->values_min)) {
if (defined (my $values_max = $self->values_max)) {
if ($values_min == $values_max) {
# constant seq is non-decreasing
return 1;
}
}
}
my $planepath_object = $self->{'planepath_object'};
my $func;
return
(($func = ($planepath_object->can("_NumSeq_Delta_$self->{'delta_type'}_non_decreasing")
|| ($self->{'delta_type'} eq 'DSquared'
&& $planepath_object->can("_NumSeq_Delta_Dist_non_decreasing"))
|| ($self->{'delta_type'} eq 'TDSquared'
&& $planepath_object->can("_NumSeq_Delta_TDist_non_decreasing"))))
? $planepath_object->$func()
: $self->characteristic_increasing); # increasing means non_decreasing too
}
sub _dir360_to_tdir6 {
my ($a) = @_;
if ($a % 90 == 0) {
# 0,90,180,270 -> 0, 1.5, 3, 4.5
return $a / 60;
}
if ($a % 45 == 0) {
# 45, 135, 225, 315 -> 1, 2, 4, 5
return ($a+45)/90 + ($a < 180 ? 0 : 1);
}
if ($a == 30) { return 0.75; }
if ($a == 150) { return 2.25; }
if ($a == 210) { return 3.75; }
if ($a == 330) { return 5.25; }
$a *= _PI/180; # degrees to radians
my $tdir6 = atan2(sin($a)*sqrt(3), cos($a))
* (3/_PI); # radians to 6
return ($tdir6 < 0 ? $tdir6 + 6 : $tdir6);
}
sub _dxdy_to_dir4 {
my ($dx,$dy) = @_;
### _dxdy_to_dir4(): "$dx,$dy"
if ($dy == 0) {
### dy=0 ...
return ($dx == 0 ? 4 : $dx > 0 ? 0 : 2);
}
if ($dx == 0) {
### dx=0 ...
return ($dy > 0 ? 1 : 3);
}
if ($dx > 0) {
if ($dx == $dy) { return 0.5; }
if ($dx == -$dy) { return 3.5; }
} else {
if ($dx == $dy) { return 2.5; }
if ($dx == -$dy) { return 1.5; }
}
# don't atan2() in bigints
if (ref $dx && $dx->isa('Math::BigInt')) {
$dx = $dx->numify;
}
if (ref $dy && $dy->isa('Math::BigInt')) {
$dy = $dy->numify;
}
# Crib: atan2() returns -PI <= a <= PI, and perlfunc says atan2(0,0) is
# "not well defined", though glibc gives 0
#
### atan2: atan2($dy,$dx)
my $dir4 = atan2($dy,$dx) * (2 / _PI);
### $dir4
return ($dir4 < 0 ? $dir4 + 4 : $dir4);
}
{
my %values_min = (dX => 'dx_minimum',
dY => 'dy_minimum',
AbsdX => 'absdx_minimum',
AbsdY => 'absdy_minimum',
dSum => 'dsumxy_minimum',
dDiffXY => 'ddiffxy_minimum',
);
sub values_min {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $method = ($values_min{$self->{'delta_type'}}
|| $planepath_object->can("_NumSeq_Delta_$self->{'delta_type'}_min"))) {
return $planepath_object->$method();
}
return undef;
}
}
{
my %values_max = (dX => 'dx_maximum',
dY => 'dy_maximum',
AbsdX => 'absdx_maximum',
AbsdY => 'absdy_maximum',
dSum => 'dsumxy_maximum',
dDiffXY => 'ddiffxy_maximum',
);
sub values_max {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $method = ($values_max{$self->{'delta_type'}}
|| $planepath_object->can("_NumSeq_Delta_$self->{'delta_type'}_max"))) {
return $planepath_object->$method();
}
return undef;
}
}
{ package Math::PlanePath;
use constant _NumSeq_Delta_oeis_anum => {};
#------------
# dX,dY
use constant _NumSeq_Delta_dX_integer => 1; # usually
use constant _NumSeq_Delta_dY_integer => 1;
#------------
# AbsdX,AbsdY
sub _NumSeq_Delta_AbsdX_integer { $_[0]->_NumSeq_Delta_dX_integer }
sub _NumSeq_Delta_AbsdY_integer { $_[0]->_NumSeq_Delta_dY_integer }
#------------
# dSum
sub _NumSeq_Delta_dSum_integer {
my ($self) = @_;
return ($self->_NumSeq_Delta_dX_integer
&& $self->_NumSeq_Delta_dY_integer);
}
#------------
# dSumAbs
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
if (! $self->x_negative && ! $self->y_negative) {
return $self->dsumxy_minimum;
}
return undef;
}
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
if (! $self->x_negative && ! $self->y_negative) {
return $self->dsumxy_maximum;
}
return undef;
}
*_NumSeq_Delta_dSumAbs_integer = \&_NumSeq_Delta_dSum_integer;
#------------
# dDiffXY
*_NumSeq_Delta_dDiffXY_integer = \&_NumSeq_Delta_dSum_integer;
#------------
# dDiffYX
sub _NumSeq_Delta_dDiffYX_min {
my ($self) = @_;
if (defined (my $m = $self->ddiffxy_maximum)) {
return -$m;
}
return undef;
}
sub _NumSeq_Delta_dDiffYX_max {
my ($self) = @_;
if (defined (my $m = $self->ddiffxy_minimum)) {
return -$m;
}
return undef;
}
sub _NumSeq_Delta_dDiffYX_integer {
return $_[0]->_NumSeq_Delta_dDiffXY_integer;
}
#------------
# dAbsDiff
*_NumSeq_Delta_dAbsDiff_integer = \&_NumSeq_Delta_dDiffYX_integer;
#------------
# dRadius, dRSquared
use constant _NumSeq_Delta_dRadius_min => undef;
use constant _NumSeq_Delta_dRadius_max => undef;
use constant _NumSeq_Delta_dRadius_integer => 0;
use constant _NumSeq_Delta_dRSquared_min => undef;
use constant _NumSeq_Delta_dRSquared_max => undef;
*_NumSeq_Delta_dRSquared_integer = \&_NumSeq_Delta_dDiffYX_integer;
#------------
# Dir4
sub _NumSeq_Delta_Dir4_min {
my ($self) = @_;
return Math::NumSeq::PlanePathDelta::_dxdy_to_dir4
($self->dir_minimum_dxdy);
}
sub _NumSeq_Delta_Dir4_max {
my ($self) = @_;
return Math::NumSeq::PlanePathDelta::_dxdy_to_dir4
($self->dir_maximum_dxdy);
}
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return ($self->_NumSeq_Delta_Dir4_max == 4);
}
use constant _NumSeq_Dir4_min_is_infimum => 0;
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
my ($dx,$dy) = $self->dir_minimum_dxdy;
if ($dx && $dy) { return 0; } # diagonal
($dx,$dy) = $self->dir_maximum_dxdy;
return ! (($dx && $dy) # diagonal
|| ($dx==0 && $dy==0)); # supremum
}
#------------
# TDir6
sub _NumSeq_Delta_TDir6_min {
my ($self) = @_;
return Math::NumSeq::PlanePathDelta::_dir360_to_tdir6
($self->_NumSeq_Delta_Dir4_min * 90);
}
sub _NumSeq_Delta_TDir6_max {
my ($self) = @_;
return Math::NumSeq::PlanePathDelta::_dir360_to_tdir6
($self->_NumSeq_Delta_Dir4_max * 90);
}
sub _NumSeq_TDir6_max_is_supremum {
return $_[0]->_NumSeq_Dir4_max_is_supremum;
}
sub _NumSeq_TDir6_min_is_infimum {
return $_[0]->_NumSeq_Dir4_min_is_infimum;
}
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
my ($dx,$dy) = $self->dir_minimum_dxdy;
if ($dy != 0 && abs($dx) != abs($dy)) { return 0; } # not diagonal or horiz
($dx,$dy) = $self->dir_maximum_dxdy;
return ! (($dy != 0 && abs($dx) != abs($dy)) # not diagonal or horiz
|| ($dx==0 && $dy==0)); # supremum
}
#------------
sub _NumSeq_Delta_Dist_min {
my ($self) = @_;
sqrt($self->_NumSeq_Delta_DSquared_min);
}
sub _NumSeq_Delta_Dist_max {
my ($self) = @_;
my $max;
return (defined ($max = $self->_NumSeq_Delta_DSquared_max)
? sqrt($max)
: undef);
}
sub _NumSeq_Delta_TDist_min {
my ($self) = @_;
sqrt($self->_NumSeq_Delta_TDSquared_min);
}
sub _NumSeq_Delta_TDist_max {
my ($self) = @_;
my $max;
return (defined ($max = $self->_NumSeq_Delta_TDSquared_max)
? sqrt($max)
: undef);
}
# Default Dist min from AbsdX,AbsdY min.
# Subclass must overridde if those minimums don't occur together.
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
my $dx = $self->absdx_minimum;
my $dy = $self->absdy_minimum;
return _max (1, $dx*$dx + $dy*$dy);
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
my $dx = $self->absdx_minimum;
my $dy = $self->absdy_minimum;
return _max (1, $dx*$dx + 3*$dy*$dy);
}
# Default Dist max from AbsdX,AbsdY max, if maximums exist.
# Subclass must overridde if those maximums don't occur together.
sub _NumSeq_Delta_DSquared_max {
my ($self) = @_;
if (defined (my $dx = $self->absdx_maximum)
&& defined (my $dy = $self->absdy_maximum)) {
return ($dx*$dx + $dy*$dy);
} else {
return undef;
}
}
sub _NumSeq_Delta_TDSquared_max {
my ($self) = @_;
if (defined (my $dx = $self->absdx_maximum)
&& defined (my $dy = $self->absdy_maximum)) {
return ($dx*$dx + 3*$dy*$dy);
} else {
return undef;
}
}
*_NumSeq_Delta_DSquared_integer = \&_NumSeq_Delta_dSum_integer;
*_NumSeq_Delta_TDSquared_integer = \&_NumSeq_Delta_dSum_integer;
use constant _NumSeq_Delta_Dir360_min => 0;
use constant _NumSeq_Delta_Dir360_max => 360;
}
{ package Math::PlanePath::SquareSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # North
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ AbsdY => 'A079813', # k 0s then k 1s plus initial 1 is abs(dY)
# OEIS-Catalogue: A079813 planepath=SquareSpiral delta_type=AbsdY
},
};
}
{ package Math::PlanePath::GreekKeySpiral;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::PyramidSpiral;
use constant _NumSeq_Delta_AbsdX_non_decreasing => 1; # constant absdx=1
use constant _NumSeq_Delta_dSumAbs_min => -2; # near diagonal, eg. N=10
use constant _NumSeq_Delta_dSumAbs_max => 2; # near diagonal, eg. N=4
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
# use constant _NumSeq_Delta_dRadius_min => -sqrt(2);
# use constant _NumSeq_Delta_dRadius_max => sqrt(2);
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::TriangleSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDSquared_min => 4; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
}
{ package Math::PlanePath::TriangleSpiralSkewed;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
{
my %_NumSeq_Delta_dAbsDiff_min = (left => -2, # North-West
right => -1, # N
up => -1, # W
down => -2); # North-West
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return $_NumSeq_Delta_dAbsDiff_min{$self->{'skew'}};
}
}
{
my %_NumSeq_Delta_dAbsDiff_max = (left => 2, # South-East
right => 1, # S
up => 1, # S
down => 2); # South-East
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return $_NumSeq_Delta_dAbsDiff_max{$self->{'skew'}};
}
}
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
# A204435 f(i,j)=((i+j )^2 mod 3), antidiagonals
# A204437 f(i,j)=((i+j+1)^2 mod 3), antidiagonals
# A204439 f(i,j)=((i+j+2)^2 mod 3), antidiagonals
# gives 0s at every third antidiagonal
use constant _NumSeq_Delta_oeis_anum =>
{ 'skew=left,n_start=1' =>
{ AbsdX => 'A204439',
AbsdY => 'A204437',
# OEIS-Catalogue: A204439 planepath=TriangleSpiralSkewed,skew=left delta_type=AbsdX
# OEIS-Catalogue: A204437 planepath=TriangleSpiralSkewed,skew=left delta_type=AbsdY
},
'skew=right,n_start=1' =>
{ AbsdX => 'A204435',
AbsdY => 'A204437',
# OEIS-Catalogue: A204435 planepath=TriangleSpiralSkewed,skew=right delta_type=AbsdX
# OEIS-Other: A204437 planepath=TriangleSpiralSkewed,skew=right delta_type=AbsdY
},
'skew=up,n_start=1' =>
{ AbsdX => 'A204439',
AbsdY => 'A204435',
# OEIS-Other: A204439 planepath=TriangleSpiralSkewed,skew=up delta_type=AbsdX
# OEIS-Other: A204435 planepath=TriangleSpiralSkewed,skew=up delta_type=AbsdY
},
'skew=down,n_start=1' =>
{ AbsdX => 'A204435',
AbsdY => 'A204439',
# OEIS-Other: A204435 planepath=TriangleSpiralSkewed,skew=down delta_type=AbsdX
# OEIS-Other: A204439 planepath=TriangleSpiralSkewed,skew=down delta_type=AbsdY
},
};
}
{ package Math::PlanePath::DiamondSpiral;
use constant _NumSeq_Delta_AbsdX_non_decreasing => 1; # constant absdx=1
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=1' =>
{ AbsdX => 'A000012', # all 1s, starting OFFSET=1
# OEIS-Other: A000012 planepath=DiamondSpiral delta_type=AbsdX
},
'n_start=0' =>
{ dSumAbs => 'A003982', # characteristic of A001844 Y_neg axis
# catalogue here in absence of anything else in NumSeq
# OEIS-Catalogue: A003982 planepath=DiamondSpiral,n_start=0 delta_type=dSumAbs
},
};
}
{ package Math::PlanePath::AztecDiamondRings;
use constant _NumSeq_Delta_dSumAbs_min => -1; # change of diamond
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=0' =>
{ AbsdY => 'A023532', # 0 at n=k*(k+3)/2, 1 otherwise
# OEIS-Catalogue: A023532 planepath=AztecDiamondRings,n_start=0 delta_type=AbsdY
},
};
}
{ package Math::PlanePath::PentSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -3;
use constant _NumSeq_Delta_dAbsDiff_max => 3;
use constant _NumSeq_Delta_dRadius_min => -2;
use constant _NumSeq_Delta_dRadius_max => 2; # at N=1
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # top dx=2,dy=1
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 5;
}
{ package Math::PlanePath::PentSpiralSkewed;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1; # at N=1
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::HexSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
sub _NumSeq_Delta_dRadius_min {
my ($self) = @_;
return ($self->{'wider'} < 2 ? -sqrt(2)
: -2); # exact -2 along initial horizontal
}
use constant _NumSeq_Delta_dRadius_max => 2;
sub _NumSeq_dRadius_min_is_infimum {
my ($self) = @_;
return ($self->{'wider'} < 2);
}
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::HexSpiralSkewed;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
sub _NumSeq_dRadius_min_is_infimum {
my ($self) = @_;
return ($self->{'wider'} == 0);
}
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::HeptSpiralSkewed;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
use constant _NumSeq_Delta_TDir6_integer => 0; # North
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::OctagramSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
}
{ package Math::PlanePath::AnvilSpiral;
use constant _NumSeq_Delta_AbsdX_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_oeis_anum =>
{ 'wider=0,n_start=0' =>
{ AbsdX => 'A000012', # all 1s, OFFSET=0
# OEIS-Other: A000012 planepath=AnvilSpiral,n_start=0 delta_type=AbsdX
},
};
}
{ package Math::PlanePath::KnightSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -3;
use constant _NumSeq_Delta_dSumAbs_max => 3;
use constant _NumSeq_Delta_dAbsDiff_min => -3;
use constant _NumSeq_Delta_dAbsDiff_max => 3;
use constant _NumSeq_Delta_DSquared_min => 2*2+1*1; # dX=1,dY=2
use constant _NumSeq_Delta_DSquared_max => 2*2+1*1;
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_min => 2*2 + 3*1*1; # dX=2,dY=1
use constant _NumSeq_Delta_TDSquared_max => 1*1 + 3*2*2; # dX=1,dY=2
}
{ package Math::PlanePath::CretanLabyrinth;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1;
}
{ package Math::PlanePath::SquareArms;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1/sqrt(2);
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_DSquared_max => 1;
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3; # vertical
}
{ package Math::PlanePath::DiamondArms; # diag always
use constant _NumSeq_Delta_AbsdX_non_decreasing => 1; # constant absdx=1
use constant _NumSeq_Delta_AbsdY_non_decreasing => 1; # constant absdy=1
use constant _NumSeq_Delta_dSumAbs_min => 0; # only outwards
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => sqrt(2);
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2; # diagonal always
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_min => 4; # diagonal always
use constant _NumSeq_Delta_TDSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1;
}
{ package Math::PlanePath::HexArms;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_dRadius_min => - sqrt(2); # diagonal
use constant _NumSeq_Delta_dRadius_max => sqrt(10) - sqrt(2); # at N=4
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
}
{ package Math::PlanePath::SacksSpiral;
use constant _NumSeq_Delta_dX_integer => 0;
use constant _NumSeq_Delta_dY_integer => 0;
use constant _NumSeq_Delta_dSumAbs_min => - 2*atan2(1,0); # -pi
use constant _NumSeq_Delta_dSumAbs_max => 2*atan2(1,0); # +pi
use constant _NumSeq_AbsdX_min_is_infimum => 1;
use constant _NumSeq_Delta_dRadius_min => 0;
use constant _NumSeq_Delta_dRadius_max => 1; # at N=0 horiz along X axis
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_dRSquared_min => 1; # always R^2+1
use constant _NumSeq_Delta_dRSquared_max => 1;
use constant _NumSeq_Delta_dRSquared_integer => 1;
use constant _NumSeq_Delta_Dist_increasing => 1; # each step bigger
}
{ package Math::PlanePath::VogelFloret;
use constant _NumSeq_Delta_dX_integer => 0;
use constant _NumSeq_Delta_dY_integer => 0;
use constant _NumSeq_AbsdX_min_is_infimum => 1;
use constant _NumSeq_AbsdY_min_is_infimum => 1;
use constant _NumSeq_Delta_dRadius_min => 0; # diagonal
sub _NumSeq_Delta_dRadius_max {
my ($self) = @_;
return ($self->n_to_radius($self->n_start + 1)
- $self->n_to_radius($self->n_start));
}
use constant _NumSeq_dRadius_min_is_infimum => 1;
# R1^2 = (sqrt(N) * radius_factor)^2
# = N * radius_factor^2
# R2^2 = (N+1) * radius_factor^2
# R2^2-R1^2 = radius_factor^2 constant
#
sub _NumSeq_Delta_dRSquared_min {
my ($self) = @_;
return ($self->{'radius_factor'} ** 2);
}
*_NumSeq_Delta_dRSquared_max = \&_NumSeq_Delta_dRSquared_min;
sub _NumSeq_Delta_dRSquared_integer {
my ($self) = @_;
my $rf_squared = $self->{'radius_factor'} ** 2;
return ($rf_squared == int($rf_squared));
}
use constant _NumSeq_Dir4_min_is_infimum => 1;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::TheodorusSpiral;
use constant _NumSeq_Delta_dX_integer => 0;
use constant _NumSeq_Delta_dY_integer => 0;
use constant _NumSeq_dX_min_is_infimum => 1;
use constant _NumSeq_dY_min_is_infimum => 1;
use constant _NumSeq_dSum_min_is_infimum => 1;
use constant _NumSeq_dSum_max_is_supremum => 1;
use constant _NumSeq_Delta_dSumAbs_min => -1; # supremum vert/horiz
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_dSumAbs_min_is_infimum => 1;
use constant _NumSeq_dDiffXY_min_is_infimum => 1;
use constant _NumSeq_dDiffXY_max_is_supremum => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -sqrt(2); # supremum diagonal
use constant _NumSeq_Delta_dAbsDiff_max => sqrt(2);
use constant _NumSeq_dAbsDiff_min_is_infimum => 1;
use constant _NumSeq_dAbsDiff_max_is_supremum => 1;
use constant _NumSeq_Delta_dRadius_min => 0;
use constant _NumSeq_Delta_dRadius_max => 1; # at N=0
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_dRSquared_min => 1; # always R^2+1
use constant _NumSeq_Delta_dRSquared_max => 1;
use constant _NumSeq_Delta_dRSquared_integer => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # constant 1
use constant _NumSeq_Delta_Dist_non_decreasing => 1; # constant 1
use constant _NumSeq_Delta_TDSquared_max => 3; # vertical
}
{ package Math::PlanePath::ArchimedeanChords;
use constant _NumSeq_Delta_dX_integer => 0;
use constant _NumSeq_Delta_dY_integer => 0;
use constant _NumSeq_dX_min_is_infimum => 1;
use constant _NumSeq_AbsdX_min_is_infimum => 1;
use constant _NumSeq_dY_min_is_infimum => 1;
use constant _NumSeq_dY_max_is_supremum => 1;
use constant _NumSeq_dSum_min_is_infimum => 1;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_dSumAbs_min_is_infimum => 1;
use constant _NumSeq_dDiffXY_min_is_infimum => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -sqrt(2); # supremum when diagonal
use constant _NumSeq_Delta_dAbsDiff_max => sqrt(2);
use constant _NumSeq_dAbsDiff_min_is_infimum => 1;
use constant _NumSeq_Delta_dRadius_min => 0;
use constant _NumSeq_Delta_dRadius_max => 1; # at N=0
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_dRSquared_min => -1/(4*atan2(1,1)); # -1/pi
use constant _NumSeq_Delta_dRSquared_max => 1; # at N=0
use constant _NumSeq_Delta_DSquared_max => 1;
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3; # supremum
use constant _NumSeq_TDSquared_max_is_supremum => 1;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::MultipleRings;
#---------
# dX
sub _NumSeq_dX_min_is_infimum {
my ($self) = @_;
if ($self->{'step'} == 0) {
return 0; # horizontal only, exact
}
return 1; # infimum
}
sub _NumSeq_dX_max_is_supremum {
my ($self) = @_;
return ($self->{'step'} <= 6
? 0
: 1); # supremum
}
sub _NumSeq_Delta_dX_non_decreasing {
my ($self) = @_;
return ($self->{'step'} == 0); # constant dX=1,dY=0
}
*_NumSeq_Delta_dX_integer = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dY
*_NumSeq_dY_max_is_supremum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_dY_min_is_infimum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_Delta_dY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dY_integer = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# AbsdX
sub _NumSeq_AbsdX_min_is_infimum {
my ($self) = @_;
if ($self->{'step'} == 1) {
return 0; # horizontal only
}
if ($self->{'step'} % 2 == 1) {
return 0; # any odd num sides has left vertical dX=0 exactly
}
return $self->_NumSeq_dX_min_is_infimum;
}
*_NumSeq_Delta_AbsdX_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# AbsdY
sub _NumSeq_Delta_AbsdY_non_decreasing {
my ($self) = @_;
if ($self->{'ring_shape'} eq 'polygon' && $self->{'step'} == 4) {
return 1; # abs(dY) constant
}
return $self->_NumSeq_Delta_dY_non_decreasing;
}
#---------
# dSum
*_NumSeq_dSum_max_is_supremum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_dSum_min_is_infimum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_Delta_dSum_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dDiffXY
*_NumSeq_dDiffXY_min_is_infimum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_dDiffXY_max_is_supremum = \&_NumSeq_dX_min_is_infimum;
*_NumSeq_Delta_dDiffXY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dDiffYX
*_NumSeq_Delta_dDiffYX_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dSumAbs
*_NumSeq_Delta_dSumAbs_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dAbsDiff
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # always dX=+1,dY=0 so d(abs(X-Y))=1 always
# FIXME: side length some maximum?
: undef);
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # always dX=+1,dY=0 so d(abs(X-Y))=1 always
# FIXME: side length some maximum?
: undef);
}
*_NumSeq_Delta_dAbsDiff_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#---------
# dRadius,dRSquared
sub _NumSeq_Delta_dRadius_min {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1 # step=1 always dRadius=+1
: $self->{'ring_shape'} eq 'circle' ? 0 # within circle dRadius=0
: undef);
}
sub _NumSeq_Delta_dRadius_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1 # always dRSquared=+1
: $self->{'ring_shape'} eq 'circle' ? 1
: undef);
}
sub _NumSeq_Delta_dRadius_integer {
my ($self) = @_;
return ($self->{'step'} <= 1 || $self->{'step'} == 6);
}
*_NumSeq_Delta_dRSquared_min = \&_NumSeq_Delta_dRadius_min;
*_NumSeq_Delta_dRSquared_increasing = \&_NumSeq_Delta_dX_non_decreasing; # step==0
*_NumSeq_Delta_dRSquared_integer = \&_NumSeq_Delta_dRadius_integer;
#---------
# DSquared
sub _NumSeq_Delta_DSquared_max {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # horizontal only
: $self->{'step'} <= 6
? ((8*atan2(1,1)) / $self->{'step'}) ** 2
# step > 6, between rings
: ((0.5/_PI()) * $self->{'step'}) ** 2);
}
*_NumSeq_Delta_Dist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
#-----------
# Dir4,TDir6
*_NumSeq_Delta_Dir4_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_integer = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_integer = \&_NumSeq_Delta_dX_non_decreasing;
use constant _NumSeq_Delta_oeis_anum =>
{
# MultipleRings step=0 is trivial X=N,Y=0
'step=0,ring_shape=circle' =>
{ dX => 'A000012', # all 1s
dY => 'A000004', # all-zeros
Dir4 => 'A000004', # all zeros, East
TDir6 => 'A000004', # all zeros, East
# OEIS-Other: A000012 planepath=MultipleRings,step=0 delta_type=dX
# OEIS-Other: A000004 planepath=MultipleRings,step=0 delta_type=dY
# OEIS-Other: A000004 planepath=MultipleRings,step=0 delta_type=Dir4
# OEIS-Other: A000004 planepath=MultipleRings,step=0 delta_type=TDir6
},
};
}
{ package Math::PlanePath::PixelRings; # NSEW+diag
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 5; # dx=2,dy=1 at jump N=5 to N=6
}
{ package Math::PlanePath::FilledRings; # NSEW+diag
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::Hypot;
use constant _NumSeq_Delta_dRadius_min => 0;
use constant _NumSeq_Delta_dRSquared_min => 0;
{
my %_NumSeq_Delta_dRadius_max = (all => 1,
even => sqrt(2), # N=1
odd => sqrt(5)-1, # N=4 0,1 -> 2,1
);
sub _NumSeq_Delta_dRadius_max {
my ($self) = @_;
return $_NumSeq_Delta_dRadius_max{$self->{'points'}};
}
}
# approaches horizontal
use constant _NumSeq_Dir4_max_is_supremum => 1;
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 2); # dX=1,dY=1
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 4); # dX=1,dY=1
}
}
{ package Math::PlanePath::HypotOctant;
use constant _NumSeq_Delta_dRadius_min => 0;
use constant _NumSeq_Delta_dRSquared_min => 0;
{
my %_NumSeq_Delta_dRadius_max = (all => 1, # N=1
even => sqrt(2), # N=1
odd => sqrt(5)-1, # N=1 1,0 -> 2,1
);
sub _NumSeq_Delta_dRadius_max {
my ($self) = @_;
return $_NumSeq_Delta_dRadius_max{$self->{'points'}};
}
}
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 2); # dX=1,dY=1
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 4); # dX=1,dY=1
}
use constant _NumSeq_Delta_TDir6_integer => 0;
}
{ package Math::PlanePath::TriangularHypot;
# approaches horizontal
use constant _NumSeq_Dir4_max_is_supremum => 1;
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 2); # dX=1,dY=1
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # dX=1,dY=0
: 4); # dX=1,dY=1
}
}
{ package Math::PlanePath::PythagoreanTree;
{
my %_NumSeq_Delta_dRadius_integer = ('AB' => 1, # Radius=C
'SM' => 1, # Radius=C
);
sub _NumSeq_Delta_dRadius_integer {
my ($self) = @_;
return $_NumSeq_Delta_dRadius_integer{$self->{'coordinates'}};
}
}
{
my %Dir4_min_is_infimum = ('BC,UAD' => 1,
'SM,UAD' => 1,
'SC,UAD' => 1,
'MC,UAD' => 1,
'AB,FB' => 1,
'AC,FB' => 1,
'BC,FB' => 1,
'PQ,FB' => 1,
'SM,FB' => 1,
'SC,FB' => 1,
'MC,FB' => 1,
'AC,UMT' => 1,
'SM,UMT' => 1,
'SC,UMT' => 1,
);
sub _NumSeq_Dir4_min_is_infimum {
my ($self) = @_;
return $Dir4_min_is_infimum{"$self->{'coordinates'},$self->{'tree_type'}"};
}
}
{
my %Dir4_max_is_supremum = ('BC,UAD' => 1,
'SM,UAD' => 1,
'SC,UAD' => 1,
'MC,UAD' => 1,
'AB,FB' => 1,
'AC,FB' => 1,
'PQ,FB' => 1,
'SM,FB' => 1,
'SC,FB' => 1,
'MC,FB' => 1,
'AB,UMT' => 1,
'BC,UMT' => 1,
'SM,UMT' => 1,
'SC,UMT' => 1,
'MC,UMT' => 1,
);
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return $Dir4_max_is_supremum{"$self->{'coordinates'},$self->{'tree_type'}"};
}
}
use constant _NumSeq_Delta_TDir6_integer => 0;
}
{ package Math::PlanePath::RationalsTree;
{
my %Dir4_min_is_infimum = (Drib => 1);
sub _NumSeq_Dir4_min_is_infimum {
my ($self) = @_;
return $Dir4_min_is_infimum{$self->{'tree_type'}};
}
}
{
my %Dir4_max_is_supremum = (CW => 1,
AYT => 1,
Drib => 1,
L => 1);
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return $Dir4_max_is_supremum{$self->{'tree_type'}};
}
}
use constant _NumSeq_Delta_TDir6_integer => 0; # vertical
use constant _NumSeq_Delta_oeis_anum =>
{ 'tree_type=L' =>
{ dY => 'A070990', # Stern diatomic differences OFFSET=0
# OEIS-Catalogue: A070990 planepath=RationalsTree,tree_type=L delta_type=dY
},
# 'tree_type=CW' =>
# {
# # dY => 'A070990', # Stern diatomic first diffs, except it starts i=0
# # where RationalsTree N=1. dX is same, but has extra leading 0.
# },
};
}
{ package Math::PlanePath::FractionsTree;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::ChanTree;
sub _NumSeq_Dir4_min_is_infimum {
my ($self) = @_;
return ($self->{'k'} == 2 || ($self->{'k'} & 1) == 0
? 0 # k=2 or k odd
: 1); # k even
}
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::DiagonalRationals;
use constant _NumSeq_TDSquared_min => 3;
}
{ package Math::PlanePath::FactorRationals;
use constant _NumSeq_Dir4_min_is_infimum => 1;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::CfracDigits;
# radix=1 N=1 has dir4=0
# radix=2 N=5628 has dir4=0 dx=9,dy=0
# radix=3 N=1189140 has dir4=0 dx=1,dy=0
# radix=4 N=169405 has dir4=0 dx=2,dy=0
# always eventually 0 ?
sub _NumSeq_Dir4_min_is_infimum {
my ($self) = @_;
return ($self->{'radix'} > 4);
}
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::GcdRationals;
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'pairs_order'} eq 'diagonals_down'
? 3 # at N=1 vert
: 1); # at N=4 horiz
}
use constant _NumSeq_Delta_TDir6_integer => 0; # vertical
}
{ package Math::PlanePath::PeanoCurve;
*_NumSeq_Delta_dAbsDiff_min = \&dx_minimum;
*_NumSeq_Delta_dAbsDiff_max = \&dx_maximum;
*_NumSeq_Delta_DSquared_max = \&dx_maximum;
sub _NumSeq_Delta_Dist_non_decreasing {
my ($self) = @_;
return ($self->{'radix'} % 2
? 1 # odd
: 0); # even, jumps about
}
sub _NumSeq_Delta_TDSquared_max {
my ($self) = @_;
return ($self->{'radix'} % 2
? 3 # odd, vertical
: undef); # even, unlimited
}
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return ($self->{'radix'} % 2
? 1 # odd, continuous path
: 0); # even, jumps
}
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return ($self->{'radix'} % 2
? 0 # odd
: 1); # even, supremum
}
# use constant _NumSeq_Delta_oeis_anum =>
# { 'radix=3' =>
# {
# # Not quite, extra initial 0
# # AbsdX => 'A014578', # 1 - count low 0-digits, mod 2
# # # OEIS-Catalogue: A014578 planepath=PeanoCurve delta_type=AbsdX
#
# # # Not quite, OFFSET n=1 cf N=0
# # # # A163534 is 0=east,1=south,2=west,3=north treated as down page,
# # # # which corrsponds to 1=north (incr Y), 3=south (decr Y) for
# # # # directions of the PeanoCurve planepath here
# # # Dir4 => 'A163534',
# # # # OEIS-Catalogue: A163534 planepath=PeanoCurve delta_type=Dir4
# #
# # # delta a(n)-a(n-1), so initial dx=0 at i=0 ...
# # # dX => 'A163532',
# # # # OEIS-Catalogue: A163532 planepath=PeanoCurve delta_type=dX
# # # dY => 'A163533',
# # # # OEIS-Catalogue: A163533 planepath=PeanoCurve delta_type=dY
# },
# };
}
{ package Math::PlanePath::WunderlichSerpentine;
sub _NumSeq_Delta_dAbsDiff_min { return $_[0]->dsumxy_minimum; }
sub _NumSeq_Delta_dAbsDiff_max { return $_[0]->dsumxy_maximum; }
# radix=2 0101 is straight NSEW parts, other evens are diagonal
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return (($self->{'radix'} % 2)
|| join('',@{$self->{'serpentine_array'}}) eq '0101'
? 1 # odd, continuous path
: 0); # even, jumps
}
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return (($self->{'radix'} % 2)
|| join('',@{$self->{'serpentine_array'}}) eq '0101'
? 0 # odd, South
: 1); # even, supremum
}
*_NumSeq_Delta_DSquared_max = \&Math::PlanePath::PeanoCurve::_NumSeq_Delta_DSquared_max;
*_NumSeq_Delta_Dist_non_decreasing = \&Math::PlanePath::PeanoCurve::_NumSeq_Delta_Dist_non_decreasing;
*_NumSeq_Delta_TDSquared_max = \&Math::PlanePath::PeanoCurve::_NumSeq_Delta_TDSquared_max;
}
{ package Math::PlanePath::HilbertCurve;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
# 'Math::PlanePath::HilbertCurve' =>
# {
# # Not quite, OFFSET=1 at origin, cf path N=0
# # # A163540 is 0=east,1=south,2=west,3=north for drawing down the page,
# # # which corresponds to 1=north,3=south per the HilbertCurve planepath
# # Dir4 => 'A163540',
# # # OEIS-Catalogue: A163540 planepath=HilbertCurve delta_type=Dir4
#
# Not quite, # delta path(n)-path(n-1) starting i=0 with path(-1)=0 for
# first value 0
# # dX => 'A163538',
# # # OEIS-Catalogue: A163538 planepath=HilbertCurve delta_type=dX
# # dY => 'A163539',
# # # OEIS-Catalogue: A163539 planepath=HilbertCurve delta_type=dY
# #
# # cf A163541 absolute direction, transpose X,Y
# # would be N=0,E=1,S=2,W=3
# },
}
{ package Math::PlanePath::HilbertSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
# { package Math::PlanePath::HilbertMidpoints;
# use constant _NumSeq_Delta_DSquared_min => 2;
# use constant _NumSeq_Delta_DSquared_max => 4;
# }
{ package Math::PlanePath::ZOrderCurve;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
}
{ package Math::PlanePath::GrayCode;
sub _NumSeq_Delta_dSumAbs_min { return $_[0]->dsumxy_minimum; }
sub _NumSeq_Delta_dSumAbs_max { return $_[0]->dsumxy_maximum; }
sub _NumSeq_Delta_dAbsDiff_min { return $_[0]->ddiffxy_minimum; }
sub _NumSeq_Delta_dAbsDiff_max { return $_[0]->ddiffxy_maximum; }
{
my %Dir4_integer = (reflected => { TsF => 1,
FsT => 1,
Ts => 1,
Fs => 1,
},
modular => { TsF => 1,
Ts => 1,
},
);
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
my $gray_type = ($self->{'radix'} == 2
? 'reflected'
: $self->{'gray_type'});
return $Dir4_integer{$gray_type}->{$self->{'apply_type'}};
}
}
use constant _NumSeq_Delta_TDir6_integer => 0;
sub _NumSeq_Delta_Dist_non_decreasing {
my ($self) = @_;
return ($self->{'radix'} % 2
&& $self->{'gray_type'} eq 'reflected'
&& ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'FsT')
? 1 # PeanoCurve style NSEW only
: 0);
}
}
{ package Math::PlanePath::ImaginaryBase;
# Dir4 radix=2 goes south-east at
# N=2^3-1=7
# N=2^7-1=127
# N=2^11-1=2047
# N=2^15-1=32767
# dx=0x555555
# dy=-0xAAAAAB
# approaches dx=1,dy=-2
#
# radix=3
# dy=dx+1 approches SE
#
# radix=4 dx/dy=1.5
# radix=5 dx/dy=2
# dx/dy=(radix-1)/2
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0;
}
{ package Math::PlanePath::ImaginaryHalf;
{
my %_NumSeq_Dir4_min_is_infimum = (XYX => 0,
XXY => 0,
YXX => 1, # dX=big,dY=1
XnYX => 1, # dX=big,dY=1
XnXY => 0, # dX=1,dY=0 at N=1
YXnX => 1, # dX=big,dY=1
);
sub _NumSeq_Dir4_min_is_infimum {
my ($self) = @_;
return $_NumSeq_Dir4_min_is_infimum{$self->{'digit_order'}};
}
}
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0;
}
{ package Math::PlanePath::CubicBase;
use constant _NumSeq_Delta_DSquared_min => 4; # at X=0 to X=2
# direction supremum maybe at
# dx=-0b 1001001001001001... = - (8^k-1)/7
# dy=-0b11011011011011011... = - (3*8^k-1)/7
# which is
# dx=-1, dy=-3
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_TDSquared_min => 4; # at N=0 dX=2,dY=1
}
# { package Math::PlanePath::Flowsnake;
# # inherit from FlowsnakeCentres
# }
{ package Math::PlanePath::FlowsnakeCentres;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
# dRadius_min at arms=1 N=8591
# arms=2 N=85
# arms=3 N=127
use constant _NumSeq_Delta_dRadius_min => -2;
use constant _NumSeq_Delta_dRadius_max => 2; # at N=0
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::GosperReplicate;
# maximum angle N=34 dX=3,dY=-1, it seems
}
{ package Math::PlanePath::GosperIslands;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # between islands
}
{ package Math::PlanePath::GosperSide;
use constant _NumSeq_Delta_dSumAbs_min => -2; # diagonals
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
# use constant _NumSeq_Delta_oeis_anum =>
# 'Math::PlanePath::GosperSide' =>
# 'Math::PlanePath::TerdragonCurve' =>
# A062756 is total turn starting OFFSET=0, count of ternary 1 digits.
# Dir6 would be total%6, or 2*(total%3) for Terdragon, suspect such a
# modulo version not in OEIS.
}
{ package Math::PlanePath::KochCurve;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_oeis_anum =>
{ '' =>
{ AbsdY => 'A011655', # 0,1,1 repeating
# OEIS-Catalogue: A011655 planepath=KochCurve delta_type=AbsdY
},
};
}
{ package Math::PlanePath::KochPeaks;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_DSquared_min => 2;
}
{ package Math::PlanePath::KochSnowflakes;
use constant _NumSeq_Delta_dX_integer => 1;
use constant _NumSeq_Delta_dY_integer => 0; # initial Y=+2/3
use constant _NumSeq_Delta_DSquared_min => 2; # step diag or 2straight
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
use constant _NumSeq_Delta_TDir6_integer => 0; # between rings
}
{ package Math::PlanePath::KochSquareflakes;
use constant _NumSeq_Delta_dX_integer => 0; # initial non-integers
use constant _NumSeq_Delta_dY_integer => 0;
use constant _NumSeq_Delta_dSum_integer => 1;
use constant _NumSeq_Delta_dSumAbs_integer => 1;
use constant _NumSeq_Delta_dDiffXY_integer => 1;
use constant _NumSeq_Delta_dAbsDiff_integer => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # between rings
}
{ package Math::PlanePath::QuadricCurve;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::QuadricIslands;
use constant _NumSeq_Delta_dX_integer => 0; # initial 0.5s
use constant _NumSeq_Delta_dY_integer => 0;
# minimum unbounded jumping to next ring
use constant _NumSeq_Delta_dSum_integer => 1; # 0.5+0.5 integer
# maximum unbounded jumping to next ring
use constant _NumSeq_Delta_dSumAbs_min => -1; # at N=5
use constant _NumSeq_Delta_dSumAbs_integer => 1; # 0.5+0.5 integer
use constant _NumSeq_Delta_dDiffXY_integer => 1; # dDiffXY=+1 or -1
# dAbsDiff=+1 or -1
# jump to next ring is along leading diagonal so dAbsDiff bounded
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dAbsDiff_integer => 1; # 0.5-0.5 integer
use constant _NumSeq_Delta_Dir4_integer => 0; # between islands
}
{ package Math::PlanePath::SierpinskiCurve;
sub _NumSeq_Delta_dSumAbs_min { return $_[0]->dsumxy_minimum; }
sub _NumSeq_Delta_dSumAbs_max { return $_[0]->dsumxy_maximum; }
sub _NumSeq_Delta_dAbsDiff_min { return $_[0]->ddiffxy_minimum; }
sub _NumSeq_Delta_dAbsDiff_max { return $_[0]->ddiffxy_maximum; }
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return ($self->{'diagonal_spacing'} == 0);
}
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'straight_spacing'} == 0);
}
use List::Util;
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
return List::Util::min ($self->{'straight_spacing'} ** 2,
2 * $self->{'diagonal_spacing'} ** 2);
}
sub _NumSeq_Delta_DSquared_max {
my ($self) = @_;
return List::Util::max ($self->{'straight_spacing'} ** 2,
2 * $self->{'diagonal_spacing'} ** 2);
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return List::Util::min($self->{'straight_spacing'},
2 * $self->{'diagonal_spacing'}) ** 2;
}
sub _NumSeq_Delta_TDSquared_max {
my ($self) = @_;
return List::Util::max(3 * $self->{'straight_spacing'} ** 2, # vertical
4 * $self->{'diagonal_spacing'} ** 2);
}
# use constant _NumSeq_Delta_oeis_anum =>
# 'arms=1,straight_spacing=1,diagonal_spacing=1' =>
# {
# # # Not quite, A127254 has extra initial 1
# # AbsdY => 'A127254', # 0 at 2*position of "odious" odd number 1-bits
# # # OEIS-Catalogue: A127254 planepath=SierpinskiCurve delta_type=AbsdY
# },
}
{ package Math::PlanePath::SierpinskiCurveStair;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ 'arms=1' =>
{ AbsdX => 'A059841', # 1,0 repeating
AbsdY => 'A000035', # 0,1 repeating
# OEIS-Other: A059841 planepath=SierpinskiCurveStair delta_type=AbsdX
# OEIS-Other: A000035 planepath=SierpinskiCurveStair delta_type=AbsdY
#
# OEIS-Other: A059841 planepath=SierpinskiCurveStair,diagonal_length=2 delta_type=AbsdX
# OEIS-Other: A059841 planepath=SierpinskiCurveStair,diagonal_length=3 delta_type=AbsdX
# OEIS-Other: A000035 planepath=SierpinskiCurveStair,diagonal_length=2 delta_type=AbsdY
# OEIS-Other: A000035 planepath=SierpinskiCurveStair,diagonal_length=3 delta_type=AbsdY
},
};
}
{ package Math::PlanePath::SierpinskiTriangle;
use constant _NumSeq_Delta_DSquared_min => 2;
sub _NumSeq_Delta_dSumAbs_min { return $_[0]->dsumxy_minimum; }
sub _NumSeq_Delta_dSumAbs_max { return $_[0]->dsumxy_maximum; }
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return ($self->{'align'} ne 'diagonal');
}
use constant _NumSeq_Delta_Dir4_integer => 0; # between rows
use constant _NumSeq_Delta_TDir6_integer => 0; # between rows
}
{ package Math::PlanePath::SierpinskiArrowhead;
{
my %_NumSeq_Delta_dSumAbs_min = (triangular => -2,
left => -2,
right => -2,
diagonal => -1,
);
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
return $_NumSeq_Delta_dSumAbs_min{$self->{'align'}};
}
}
{
my %_NumSeq_Delta_dSumAbs_max = (triangular => 2,
left => 2,
right => 2,
diagonal => 1,
);
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
return $_NumSeq_Delta_dSumAbs_max{$self->{'align'}};
}
}
sub _NumSeq_Delta_dAbsDiff_min { return $_[0]->ddiffxy_minimum; }
sub _NumSeq_Delta_dAbsDiff_max { return $_[0]->ddiffxy_maximum; }
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'align'} eq 'triangular' ? 1 : 0);
}
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::SierpinskiArrowheadCentres;
*_NumSeq_Delta_dSumAbs_min
= \&Math::PlanePath::SierpinskiArrowhead::_NumSeq_Delta_dSumAbs_min;
*_NumSeq_Delta_dSumAbs_max
= \&Math::PlanePath::SierpinskiArrowhead::_NumSeq_Delta_dSumAbs_max;
sub _NumSeq_Delta_dAbsDiff_min { return $_[0]->ddiffxy_minimum; }
sub _NumSeq_Delta_dAbsDiff_max { return $_[0]->ddiffxy_maximum; }
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'align'} eq 'triangular' ? 1 : 0);
}
sub _NumSeq_Delta_dDSquared_min {
my ($self) = @_;
return ($self->{'align'} eq 'triangular' ? 2 : 1);
}
sub _NumSeq_Delta_dDSquared_max {
my ($self) = @_;
return ($self->{'align'} eq 'triangular' ? 4 : 2);
}
}
{ package Math::PlanePath::DragonCurve;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{
do {
my $href =
{ AbsdX => 'A059841', # 1,0 repeating
AbsdY => 'A000035', # 0,1 repeating
};
('arms=1' => $href,
'arms=3' => $href,
);
# OEIS-Other: A059841 planepath=DragonCurve delta_type=AbsdX
# OEIS-Other: A000035 planepath=DragonCurve delta_type=AbsdY
# OEIS-Other: A059841 planepath=DragonCurve,arms=3 delta_type=AbsdX
# OEIS-Other: A000035 planepath=DragonCurve,arms=3 delta_type=AbsdY
},
# 'arms=2' => $href,# 0,1,1,0
'arms=4' =>
{ AbsdY => 'A165211', # 0,1,0,1, 1,0,1,0, repeating
# OEIS-Other: A165211 planepath=DragonCurve,arms=4 delta_type=AbsdY
},
};
}
{ package Math::PlanePath::DragonRounded;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
# dRadius infimum/supremum because diagonals only occur on "odd" diagonals,
# never on the X=Y diagonal, so never have step by sqrt(2) exactly
use constant _NumSeq_Delta_dRadius_min => -sqrt(2);
use constant _NumSeq_Delta_dRadius_max => sqrt(2);
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_dRadius_max_is_supremum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_oeis_anum =>
{ 'arms=1' =>
{ AbsdX => 'A152822', # 1,1,0,1 repeating
AbsdY => 'A166486', # 0,1,1,1 repeating
# OEIS-Catalogue: A166486 planepath=DragonRounded delta_type=AbsdY
# OEIS-Catalogue: A152822 planepath=DragonRounded delta_type=AbsdX
},
};
}
{ package Math::PlanePath::DragonMidpoint;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1; # at N=1534
use constant _NumSeq_Delta_dRadius_max => 1; # at N=0
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
# use constant _NumSeq_Delta_oeis_anum =>
# '' =>
# {
# # Not quite, has n=N+2 and extra initial 0 at n=1
# # AbsdY => 'A073089',
# },
}
{ package Math::PlanePath::R5DragonCurve;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ do {
my $href =
{ AbsdX => 'A059841', # 1,0 repeating
AbsdY => 'A000035', # 0,1 repeating
};
('arms=1' => $href,
'arms=3' => $href,
);
# OEIS-Other: A059841 planepath=R5DragonCurve delta_type=AbsdX
# OEIS-Other: A000035 planepath=R5DragonCurve delta_type=AbsdY
# OEIS-Other: A059841 planepath=R5DragonCurve,arms=3 delta_type=AbsdX
# OEIS-Other: A000035 planepath=R5DragonCurve,arms=3 delta_type=AbsdY
},
'arms=4' =>
{ AbsdY => 'A165211', # 0,1,0,1, 1,0,1,0, repeating
# OEIS-Other: A165211 planepath=R5DragonCurve,arms=4 delta_type=AbsdY
},
};
}
{ package Math::PlanePath::R5DragonMidpoint;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::CCurve;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ '' =>
{ AbsdX => 'A010059', # 0,1 repeating
AbsdY => 'A010060', # 1-bit count mod 2, DigitSumModulo Thue-Morse
Dir4 => 'A179868', # 1-bit count mod 4, DigitSumModulo
# OEIS-Catalogue: A010059 planepath=CCurve delta_type=AbsdX
# OEIS-Other: A010060 planepath=CCurve delta_type=AbsdY
# OEIS-Other: A179868 planepath=CCurve delta_type=Dir4
},
};
}
{ package Math::PlanePath::AlternatePaper;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # North
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ 'arms=1' =>
{ AbsdY => 'A000035', # 0,1 repeating
dSum => 'A020985', # GRS
dSumAbs => 'A020985', # GRS
# OEIS-Other: A000035 planepath=AlternatePaper delta_type=AbsdY
# OEIS-Other: A020985 planepath=AlternatePaper delta_type=dSum
# OEIS-Other: A020985 planepath=AlternatePaper delta_type=dSumAbs
# dX_every_second_point_skipping_zeros => 'A020985', # GRS
# # ie. Math::NumSeq::GolayRudinShapiro
},
'arms=4' =>
{ dSum => 'A020985', # GRS
# OEIS-Other: A020985 planepath=AlternatePaper,arms=4 delta_type=dSum
},
};
}
{ package Math::PlanePath::AlternatePaperMidpoint;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_TDir6_integer => 0; # North
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::TerdragonCurve;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -2; # at N=157
use constant _NumSeq_Delta_dRadius_max => 2; # at N=0
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::TerdragonRounded;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -2; # at N=314
use constant _NumSeq_Delta_dRadius_max => 2; # at N=0
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::TerdragonMidpoint;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
# dRadius infimum/supremum because horizontals only occur on Y odd, so
# never have step by 2 exactly along X axis
use constant _NumSeq_Delta_dRadius_min => -2;
use constant _NumSeq_Delta_dRadius_max => 2;
use constant _NumSeq_dRadius_min_is_infimum => 1;
use constant _NumSeq_dRadius_max_is_supremum => 1;
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_DSquared_max => 4;
use constant _NumSeq_Delta_TDist_non_decreasing => 1; # triangular
use constant _NumSeq_Delta_TDSquared_max => 4; # triangular
}
{ package Math::PlanePath::ComplexPlus;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::ComplexMinus;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::ComplexRevolving;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::Rows;
sub _NumSeq_Delta_dX_non_decreasing {
my ($self) = @_;
return ($self->{'width'} <= 1
? 1 # single column only, dX=0 always
: 0);
}
sub _NumSeq_Delta_AbsdX_non_decreasing {
my ($self) = @_;
return ($self->{'width'} <= 2); # 1 or 2 is constant 0 or 1
}
# abs(X-Y) move towards and then away from X=Y diagonal by +1 and -1 in row,
# then at row end to Y axis goes
# from X=width-1, Y=k AbsDiff = abs(k-(width-1))
# to X=0, Y=k+1 AbsDiff = k+1
# dAbsDiff = k+1 - abs(k-(width-1))
# when k>=width-1 dAbsDiff = k+1 - (k-(width-1))
# = k+1 - k + (width-1)
# = 1 + width-1
# = width
# when k<=width-1 dAbsDiff = k+1 - ((width-1)-k)
# = k+1 - (width-1) + k
# = 2k+1 - width + 1
# = 2k+2 - width
# at k=0 dAbsDiff = 2-width
# at k=width-1 dAbsDiff = 2*(width-1)+2 - width
# = 2*width - 2 + 2 - width
# = width
# minimum = 2-width or -1
# maximum = width
#
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
if ($self->{'width'} == 1) { return 1; } # constant dAbsDiff=1
return List::Util::min(-1, 2 - $self->{'width'});
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return $self->{'width'};
}
*_NumSeq_Delta_dY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_AbsdY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dSum_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dDiffXY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dDiffYX_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dAbsDiff_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dSumAbs_non_decreasing # width=1 is dSumAbs=constant
= \&_NumSeq_Delta_dX_non_decreasing;
sub _NumSeq_Delta_dRadius_min {
my ($self) = @_;
return 2 - $self->{'width'};
}
use constant _NumSeq_Delta_dRadius_max => 1; # at N=1
*_NumSeq_Delta_dRadius_integer = \&_NumSeq_Delta_dX_non_decreasing;
sub _NumSeq_Delta_dRSquared_min {
my ($self) = @_;
return ($self->{'width'} == 1 ? 1
: $self->{'width'} == 2 ? 0
: undef);
}
use constant _NumSeq_Delta_dRSquared_integer => 1;
*_NumSeq_Delta_dRSquared_increasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dRSquared_increasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_integer = \&_NumSeq_Delta_dX_non_decreasing;
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'width'} == 2); # E and NW
}
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=1,width=1' =>
{ dX => 'A000004', # all zeros, X=0 always
dY => 'A000012', # all 1s
Dir4 => 'A000012', # all 1s, North
# OEIS-Other: A000004 planepath=Rows,width=1 delta_type=dX
# OEIS-Other: A000012 planepath=Rows,width=1 delta_type=dY
# OEIS-Other: A000012 planepath=Rows,width=1 delta_type=Dir4
},
'n_start=0,width=2' =>
{ dX => 'A033999', # 1,-1 repeating, OFFSET=0
dRSquared => 'A124625', # 1,0,1,2,1,4,1,6,1,8 ones and evens OFFSET=0
TDir6 => 'A010673', # 0,2 repeating, OFFSET=0
# catalogued here pending perhaps simpler implementation elsewhere
# OEIS-Catalogue: A033999 planepath=Rows,width=2,n_start=0 delta_type=dX
# OEIS-Catalogue: A124625 planepath=Rows,width=2,n_start=0 delta_type=dRSquared
# OEIS-Catalogue: A010673 planepath=Rows,width=2,n_start=0 delta_type=TDir6
},
'n_start=1,width=3' =>
{ dX => 'A061347', # 1,1,-2 repeating OFFSET=1
# OEIS-Catalogue: A061347 planepath=Rows,width=3 delta_type=dX
},
'n_start=0,width=3' =>
{ dSum => 'A131561', # 1,1,-1 repeating
dSumAbs => 'A131561', # same
# OEIS-Catalogue: A131561 planepath=Rows,width=3,n_start=0 delta_type=dSum
# OEIS-Other: A131561 planepath=Rows,width=3,n_start=0 delta_type=dSumAbs
# dY => 'A022003', # 0,0,1 repeating, decimal of 1/999
# # OEIS-Other: A022003 planepath=Rows,width=3 delta_type=dY
},
'n_start=1,width=4' =>
{ dY => 'A011765', # 0,0,0,1 repeating, starting OFFSET=1
# OEIS-Other: A011765 planepath=Rows,width=4 delta_type=dY
},
# OFFSET
# 'n_start=1,width=6' =>
# { dY => 'A172051', # 0,0,0,0,0,1 repeating decimal 1/999999
# # OEIS-Other: A172051 planepath=Rows,width=6 delta_type=dY
# },
};
}
{ package Math::PlanePath::Columns;
sub _NumSeq_Delta_AbsdY_non_decreasing {
my ($self) = @_;
return ($self->{'height'} <= 2); # 1 or 2 is constant
}
# same as Rows dAbsDiff
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
if ($self->{'height'} == 1) { return 1; } # constant dAbsDiff=1
return List::Util::min(-1, 2 - $self->{'height'});
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return $self->{'height'};
}
# same as Rows
sub _NumSeq_Delta_dRadius_min {
my ($self) = @_;
return 2 - $self->{'height'};
}
use constant _NumSeq_Delta_dRadius_max => 1; # at N=1
*_NumSeq_Delta_dRadius_integer = \&_NumSeq_Delta_dX_non_decreasing;
sub _NumSeq_Delta_dRSquared_min {
my ($self) = @_;
return ($self->{'height'} == 1 ? 1
: $self->{'height'} == 2 ? 0
: undef);
}
use constant _NumSeq_Delta_dRSquared_integer => 1;
*_NumSeq_Delta_dRSquared_increasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dRSquared_increasing = \&_NumSeq_Delta_dX_non_decreasing;
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'height'} == 1
? 1 # horizontal
: 3); # vertical
}
sub _NumSeq_Delta_dX_non_decreasing {
my ($self) = @_;
return ($self->{'height'} == 1); # constant when column only
}
*_NumSeq_Delta_dY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_AbsdX_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dSum_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dDiffXY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dDiffYX_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dAbsDiff_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_dSumAbs_non_decreasing # height=1 is dSumAbs=constant
= \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_integer = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_integer = \&_NumSeq_Delta_dX_non_decreasing;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=1,height=1' =>
{ dX => 'A000012', # all 1s
dY => 'A000004', # all zeros, Y=0 always
Dir4 => 'A000004', # all zeros, East
TDir6 => 'A000004', # all zeros, East
# OEIS-Other: A000012 planepath=Columns,height=1 delta_type=dX
# OEIS-Other: A000004 planepath=Columns,height=1 delta_type=dY
# OEIS-Other: A000004 planepath=Columns,height=1 delta_type=Dir4
# OEIS-Other: A000004 planepath=Columns,height=1 delta_type=TDir6
},
'n_start=0,height=2' =>
{ dY => 'A033999', # 1,-1 repeating
dSum => 'A059841', # 1,0 repeating, 1-n mod 2
dSumAbs => 'A059841', # same
dRSquared => 'A124625', # 1,0,1,2,1,4,1,6,1,8 ones and evens OFFSET=0
# OEIS-Other: A033999 planepath=Columns,height=2,n_start=0 delta_type=dY
# OEIS-Other: A059841 planepath=Columns,height=2,n_start=0 delta_type=dSum
# OEIS-Other: A059841 planepath=Columns,height=2,n_start=0 delta_type=dSumAbs
# OEIS-Other: A124625 planepath=Columns,height=2,n_start=0 delta_type=dRSquared
},
'n_start=0,height=3' =>
{ dSum => 'A131561', # 1,1,-1 repeating
dSumAbs => 'A131561', # same
# OEIS-Other: A131561 planepath=Columns,height=3,n_start=0 delta_type=dSum
# OEIS-Other: A131561 planepath=Columns,height=3,n_start=0 delta_type=dSumAbs
},
'n_start=1,height=3' =>
{ dY => 'A061347', # 1,1,-2 repeating
# OEIS-Other: A061347 planepath=Columns,height=3 delta_type=dY
# dX => 'A022003', # 0,0,1 repeating from frac 1/999
# # OEIS-Other: A022003 planepath=Columns,height=3 delta_type=dX
},
'n_start=1,height=4' =>
{ dX => 'A011765', # 0,0,0,1 repeating, starting OFFSET=1
# OEIS-Other: A011765 planepath=Columns,height=4 delta_type=dX
},
# OFFSET
# 'n_start=1,height=6' =>
# { dX => 'A172051', # 0,0,0,1 repeating, starting n=0
# # OEIS-Other: A172051 planepath=Columns,height=6 delta_type=dX
# },
};
}
{ package Math::PlanePath::Diagonals;
# -2
# | 0 dSumAbs
# \ | /
# \ /|\ /
# \/ | \/ 0
# /\ | /\
# / \|/ \
# ------+--------
# |\ /
# | \/ +2
# | /\
# |/
# |
# within diagonal from X=Xstart+p Y=Ystart+k-p
# to X=Xstart+p+1 Y=Ystart+k-p-1
# abs(Xstart+p+1)-abs(Xstart+p)
# if X1=Xstart+p>=0 then X2=Xstart+p+1>=0
# dAbsX = (Xstart+p+1)-(Xstart+p) = +1
# if X1=Xstart+p<0 then X2=Xstart+p+1<=0
# dAbsX = -(Xstart+p+1) - (-(Xstart+p)) = -1
# X1<0 occurs when Xstart<=-1
#
# abs(Ystart+k-p-1)-abs(Ystart+k-p)
# if Y2=Ystart+k-p-1>=0 then Y1=Ystart+k-p>=0
# dAbsY = (Ystart+k-p-1)-(Ystart+k-p) = -1
# if Y2=Ystart+k-p-1<0 then Y1=Ystart+k-p<=0
# dAbsY = -(Ystart+k-p-1) - (-(Ystart+k-p)) = +1
# Y2<0 occurs when Ystart<=-1
#
# within diagonal dAbsX = (Xstart>=0 ? 1 : -1)
# dAbsY = (Ystart>=0 ? -1 : 1)
# is dSumAbs_min =
#
# towards or away X=Y is dSumAbs=+/-2
# end of diagonal X=Xstart+k Y=Ystart
# to X=Xstart Y=Ystart+k+1
# if Xstart>=0 and Ystart>=0 then dSumAbs=dSum=1 always
#
# if Xstart<0 then from abs(X) = -(Xstart+k)
# to abs(X) = -Xstart
# dSumAbs = (-Xstart + Ystart+k+1) - (-(Xstart+k) + Ystart)
# = 2*k+1
# until (Xstart+k)>=0 and then
# dSumAbs = (-Xstart + Ystart+k+1) - (Xstart+k + Ystart)
# = -2*Xstart+1 which is >0
# so dSumAbs_max = -2*Xstart+1
#
# if Ystart<0 then from abs(Y) = -Ystart
# to abs(Y) = -(Ystart+k+1)
# dSumAbs = (Xstart + -(Ystart+k+1)) - (Xstart+k + -Ystart)
# = -2*k-1
# until (Ystart+k+1)>=0 and then
# dSumAbs = (Xstart + (Ystart+k+1)) - (Xstart+k + -Ystart)
# = 2*Ystart+1 which is <0
# so dSumAbs_min = 2*Ystart+1
#
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
my $x_start = $self->{'x_start'};
my $y_start = $self->{'y_start'};
if ($self->{'direction'} eq 'up') {
($x_start,$y_start) = ($y_start,$x_start);
}
return List::Util::min(($x_start < 0 ? -2 : 0),
2*($y_start-List::Util::min($x_start,0)) + 1);
}
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
my $x_start = $self->{'x_start'};
my $y_start = $self->{'y_start'};
if ($self->{'direction'} eq 'up') {
($x_start,$y_start) = ($y_start,$x_start);
}
return List::Util::max(($y_start < 0 ? 2 : 1),
-2*($x_start-List::Util::min($y_start,0)) + 1);
}
# step 2 along opp diagonal, except end of row jumping back up goes
#
# | T step = 2*(F-Xstart)+1
# | \ X=Y F = Ystart
# | |\ / eg. Xstart=20 Ystart=10
# | | \ / step = 2*(10-20)+1 = -19
# | +--F
# | /
# | /
# | /
# |/
# +--------
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return List::Util::min (-2, # towards X=Y diagonal
($self->{'direction'} eq 'down' ? 2 : -2)
* ($self->{'y_start'} - $self->{'x_start'}) + 1);
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return List::Util::max (2, # away from X=Y diagonal
($self->{'direction'} eq 'down' ? 2 : -2)
* ($self->{'y_start'} - $self->{'x_start'}) + 1);
}
# * R1=sqrt(X^2+Y^2)
# \ R2=sqrt((X+1)^2+(Y-1)^2)
# \ R1-R2 -> 1
# *
#
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Dir4_min_is_infimum => 1;
# * R1=X^2+Y^2
# \ R2=(X+1)^2+(Y-1)^2
# \ R2-R1 = X^2+2X+1 - (Y^2-2Y+1) - X^2 - Y^2
# * = 2X+1 - 2*Y^2 + 2Y - 1 unbounded
#
# use constant _NumSeq_Delta_dRSquared_min => undef;
# use constant _NumSeq_Delta_dRSquared_max => undef;
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? 3 # N=1 dX=0,dY=1 vertical
: 1); # N=1 dX=0,dY=1 horizontal
}
use constant _NumSeq_Delta_oeis_anum =>
{ 'direction=down,n_start=1,x_start=0,y_start=0' =>
{ dY => 'A127949',
# OEIS-Catalogue: A127949 planepath=Diagonals delta_type=dY
},
'direction=up,n_start=1,x_start=0,y_start=0' =>
{ dX => 'A127949',
# OEIS-Other: A127949 planepath=Diagonals,direction=up delta_type=dX
},
'direction=down,n_start=0,x_start=0,y_start=0' =>
{ AbsdY => 'A051340',
dSum => 'A023531', # characteristic "1" at triangulars
dSumAbs => 'A023531', # same
# OEIS-Catalogue: A051340 planepath=Diagonals,n_start=0 delta_type=AbsdY
# OEIS-Other: A023531 planepath=Diagonals,n_start=0 delta_type=dSum
# OEIS-Other: A023531 planepath=Diagonals,n_start=0 delta_type=dSumAbs
},
'direction=up,n_start=0,x_start=0,y_start=0' =>
{ AbsdX => 'A051340',
dSum => 'A023531', # characteristic "1" at triangulars
dSumAbs => 'A023531', # same
# OEIS-Other: A051340 planepath=Diagonals,direction=up,n_start=0 delta_type=AbsdX
# OEIS-Other: A023531 planepath=Diagonals,direction=up,n_start=0 delta_type=dSum
# OEIS-Other: A023531 planepath=Diagonals,direction=up,n_start=0 delta_type=dSumAbs
# Almost AbsdY=>'A051340' too, but path starts initial 0,1,1 whereas
# A051340 starts 1,1,2
},
};
}
{ package Math::PlanePath::DiagonalsAlternating;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # between diagonals
use constant _NumSeq_Delta_DSquared_max => 2;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=0' =>
{ dSum => 'A023531', # characteristic "1" at triangulars
dSumAbs => 'A023531', # same
# OEIS-Other: A023531 planepath=DiagonalsAlternating,n_start=0 delta_type=dSum
# OEIS-Other: A023531 planepath=DiagonalsAlternating,n_start=0 delta_type=dSumAbs
},
};
}
{ package Math::PlanePath::DiagonalsOctant;
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? -2 # "down"
: undef); # "up"
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? undef # "down"
: 2); # "up"
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? 3 # N=1 dX=0,dY=1 vertical
: 1); # N=1 dX=0,dY=1 horizontal
}
}
{ package Math::PlanePath::MPeaks;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => -sqrt(2);
use constant _NumSeq_Delta_dRadius_max => sqrt(2);
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_TDSquared_min => 3; # vertical
}
{ package Math::PlanePath::Staircase;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_Dir4_integer => 0; # going back to Y axis
}
{ package Math::PlanePath::StaircaseAlternating;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
{
my %_NumSeq_Delta_dAbsDiff_max = (jump => 2, # at endpoint
square => 1); # always NSEW
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return $_NumSeq_Delta_dAbsDiff_max{$self->{'end_type'}};
}
}
use constant _NumSeq_Delta_TDir6_integer => 0; # North
{
my %DSquared_max = (jump => 4,
square => 1);
sub _NumSeq_Delta_DSquared_max {
my ($self) = @_;
return $DSquared_max{$self->{'end_type'}};
}
}
{
my %Dist_non_decreasing = (jump => 0,
square => 1); # NSEW always
sub _NumSeq_Delta_Dist_non_decreasing {
my ($self) = @_;
return $Dist_non_decreasing{$self->{'end_type'}};
}
}
{
my %TDSquared_max = (jump => 12,
square => 3);
sub _NumSeq_Delta_TDSquared_max {
my ($self) = @_;
return $TDSquared_max{$self->{'end_type'}};
}
}
}
{ package Math::PlanePath::Corner;
# X=k+wider, Y=0 has abs(X-Y)=k+wider
# X=0, Y=k+1 has abs(X-Y)=k+1
# dAbsDiff = (k+1)-(k+wider)
# = 1-wider
# and also dAbsDiff=-1 when going towards X=Y diagonal
use List::Util;
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return List::Util::min(-1, 1-$self->{'wider'});
}
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_dRadius_min => - sqrt(2);
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_Dir4_min_is_infimum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # between gnomons
# use constant _NumSeq_Delta_oeis_anum =>
# { 'wider=0,n_start=0' =>
# { dSumAbs => 'A000012', # all ones, OFFSET=0
# # OEIS-Other: A000012 planepath=Corner delta_type=dSumAbs
# },
# };
}
{ package Math::PlanePath::PyramidRows;
sub _NumSeq_Delta_dSum_non_decreasing {
my ($self) = @_;
return ($self->{'step'} == 0); # constant when column only
}
# align=right
# X>=0 so SumAbs=Sum
# within row X increasing dSum=1
# end row decrease by big
# minimum = undef
# maximum = 1
#
# align=left
# within dSumAbs=-1 towards Y axis then dSumAbs=1 away
# end row X=0,Y=k SumAbs=k
# to X=-step*(k+1),Y=k+1 SumAbs=step*(k+1) + (k+1)
# dSumAbs = step*(k+1) + (k+1) - k
# = step*k + step + k + 1 - k
# = step*(k+1) + 1 big positive
# minimum = -1
# maximum = undef
#
# align=centre, step=even
# within dSumAbs=-1 towards Y axis then dSumAbs=1 away
# end row X=k*step/2, Y=k SumAbs=k*step/2 + k
# to X=-step/2*(k+1),Y=k+1 SumAbs=step/2*(k+1) + k+1
# dSumAbs = step/2*(k+1) + k+1 - (k*step/2 + k)
# = step/2*(k+1) + k+1 - k*step/2 - k
# = step/2*(k+1) +1 - k*step/2
# = step/2 +1
# minimum = -1
# maximum = step/2 +1
#
# align=centre, step=odd
# f=floor(step/2) c=ceil(step/2)=f+1
# within dSumAbs=-1 towards Y axis then dSumAbs=1 away
# end row X=k*c, Y=k SumAbs=k*c + k
# to X=-f*(k+1),Y=k+1 SumAbs=f*(k+1) + k+1
# dSumAbs = f*(k+1) + k+1 - (k*c + k)
# = f*(k+1) + k+1 - k*(f+1) - k
# = f*k +f + k+1 - k*f - k - k
# = f + 1 - k
# = (step+1)/2 - k
# minimum = big negative
# maximum = floor(step/2) + 1 when k=0 first end row
#
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
if ($self->{'step'} == 0) {
return 1; # step=0 constant dSumAbs=1
}
if ($self->{'align'} eq 'left'
|| ($self->{'align'} eq 'centre' && $self->{'step'} % 2 == 0)) {
return -1; # towards Y axis
}
return undef; # big negatives
}
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
if ($self->{'step'} == 0
|| $self->{'align'} eq 'right') {
return 1;
}
if ($self->{'align'} eq 'centre') {
return int($self->{'step'}/2) + 1;
}
return undef;
}
# abs(X-Y) move towards and then away from X=Y diagonal by +1 and -1 in row
#
# align=left
# towards X=Y diagonal so dAbsDiff=-1
# from X=0,Y=k AbsDiff = k
# to X=-(k+1)*step,Y=k+1 AbsDiff = k+1 - (-(k+1)*step)
# dAbsDiff = k+1 - (-(k+1)*step) - k
# = step*(k+1) + 1 big positive
#
# align=right
# step<=1 only towards X=Y diagonal dAbsDiff=-1
# step>=2 away from X=Y diagonal dAbsDiff=+1
# from X=k*step,Y=k AbsDiff = k*step - k
# to X=0,Y=k+1 AbsDiff = k+1
# dAbsDiff = k+1 - (k*step - k)
# = -(step-2)*k + 1
# step=1 dAbsDiff = k+1 big positive
# step=2 dAbsDiff = 1
# step=3 dAbsDiff = -k + 1 big negative
#
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
if ($self->{'step'} == 0) { # constant N dY=1
return 1;
}
if ($self->{'align'} eq 'right' && $self->{'step'} >= 3) {
return undef; # big negative
}
return -1;
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
if ($self->{'step'} == 0) { # constant N dY=1
return 1;
}
if ($self->{'align'} eq 'right' && $self->{'step'} >= 2) {
return 1;
}
return undef;
}
*_NumSeq_Delta_dAbsDiff_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
*_NumSeq_Delta_AbsdX_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
*_NumSeq_Delta_AbsdY_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
*_NumSeq_Delta_dDiffXY_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
*_NumSeq_Delta_dDiffYX_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
*_NumSeq_Delta_dSumAbs_non_decreasing = \&_NumSeq_Delta_dSum_non_decreasing;
sub _NumSeq_Delta_dRadius_min {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1
: $self->{'step'} == 1 ? undef
: -1/sqrt(2));
}
sub _NumSeq_Delta_dRadius_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1
: sqrt(2));
}
sub _NumSeq_Delta_dRadius_integer {
my ($self) = @_;
return ($self->{'step'} == 0);
}
sub _NumSeq_Delta_dRSquared_min {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1
: undef);
}
sub _NumSeq_Delta_dRSquared_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? undef
: undef);
}
sub _NumSeq_Delta_dRSquared_increasing {
my ($self) = @_;
return ($self->{'step'} == 0);
}
use constant _NumSeq_Delta_TDir6_integer => 0;
sub _NumSeq_Delta_DSquared_max {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # X=0 vertical only
: undef);
}
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return ($self->{'step'} == 0
? 0 # north only, exact
: 1); # supremum, west and 1 up
}
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # North only, integer
: 0); # otherwise fraction
}
sub _NumSeq_Delta_dX_non_decreasing {
my ($self) = @_;
return ($self->{'step'} == 0); # step=0 is dX=0,dY=1 always
}
*_NumSeq_Delta_dY_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dir4_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDir6_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_Dist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
*_NumSeq_Delta_TDist_non_decreasing = \&_NumSeq_Delta_dX_non_decreasing;
use constant _NumSeq_Delta_oeis_anum =>
{
# PyramidRows step=0 is trivial X=0,Y=N
do {
my $href = { dX => 'A000004', # all zeros, X=0 always
dY => 'A000012', # all 1s
Dir4 => 'A000012', # all 1s, North
};
('step=0,align=centre,n_start=1' => $href,
'step=0,align=right,n_start=1' => $href,
'step=0,align=left,n_start=1' => $href,
);
# OEIS-Other: A000004 planepath=PyramidRows,step=0 delta_type=dX
# OEIS-Other: A000012 planepath=PyramidRows,step=0 delta_type=dY
# OEIS-Other: A000012 planepath=PyramidRows,step=0 delta_type=Dir4
},
# PyramidRows step=1
do { # n_start=1
my $href = { dDiffYX => 'A127949',
dAbsDiff => 'A127949', # Y>=X so same as dDiffYX
};
('step=1,align=centre,n_start=1' => $href,
'step=1,align=right,n_start=1' => $href,
);
# OEIS-Other: A127949 planepath=PyramidRows,step=1 delta_type=dDiffYX
# OEIS-Other: A127949 planepath=PyramidRows,step=1 delta_type=dAbsDiff
# OEIS-Other: A127949 planepath=PyramidRows,step=1,align=right delta_type=dDiffYX
# OEIS-Other: A127949 planepath=PyramidRows,step=1,align=right delta_type=dAbsDiff
},
do { # n_start=0
my $href =
{ dY => 'A023531', # 1,0,1,0,0,1,etc, 1 if n==k(k+3)/2
AbsdY => 'A023531', # abs(dy) same
# Not quite, A167407 has an extra initial 0
# dDiffXY => 'A167407',
};
('step=1,align=centre,n_start=0' => $href,
'step=1,align=right,n_start=0' => $href,
);
# OEIS-Catalogue: A023531 planepath=PyramidRows,step=1,n_start=0 delta_type=dY
# OEIS-Other: A023531 planepath=PyramidRows,step=1,n_start=0 delta_type=AbsdY
# OEIS-Other: A023531 planepath=PyramidRows,step=1,align=right,n_start=0 delta_type=dY
# OEIS-Other: A023531 planepath=PyramidRows,step=1,align=right,n_start=0 delta_type=AbsdY
},
'step=1,align=left,n_start=0' =>
{ dY => 'A023531', # 1,0,1,0,0,1,etc, 1 if n==k(k+3)/2
AbsdY => 'A023531', # abs(dy) same
# OEIS-Other: A023531 planepath=PyramidRows,step=1,align=left,n_start=0 delta_type=dY
# OEIS-Other: A023531 planepath=PyramidRows,step=1,align=left,n_start=0 delta_type=AbsdY
},
# 'step=2,align=centre,n_start=0' =>
# {
# # Not quite, extra initial 0
# # dDiffXY => 'A010052',
# },
};
}
{ package Math::PlanePath::PyramidSides;
use constant _NumSeq_Delta_dSumAbs_min => 0; # unchanged on diagonal
use constant _NumSeq_Delta_dSumAbs_max => 1; # step to next diagonal
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_dRadius_min => -1;
use constant _NumSeq_Delta_dRadius_max => 1;
use constant _NumSeq_dRadiusY_min_is_infimum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonals
use constant _NumSeq_Delta_TDir6_integer => 1;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=1' =>
{ AbsdY => 'A049240', # 0=square,1=non-square
# OEIS-Catalogue: A049240 planepath=PyramidSides delta_type=AbsdY
# Not quite, extra initial 1 in A010052
# dSumAbs => 'A010052', 1 at n=square
},
};
}
{ package Math::PlanePath::CellularRule;
sub _NumSeq_Delta_dSum_non_decreasing {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1 # is constant dSum=+1
: undef);
}
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1 # is constant dSum=+1
: ($self->{'rule'} & 0x5F) == 0x0E # left line 2
? -1
: $self->{'rule'} == 7 ? -1
: $self->{'rule'} == 9 ? -2
: $self->{'rule'}==11 || $self->{'rule'}==43 ? -1
: $self->{'rule'} == 15 ? -1
: $self->{'rule'}==19 ? -1
: $self->{'rule'}==21 ? -1
: ($self->{'rule'} & 0x9F) == 0x17 # 0x17,...,0x7F
? -1
: $self->{'rule'}==31 ? -1
: $self->{'rule'}==41 ? -1
: $self->{'rule'}==47 ? -1
: $self->{'rule'}==62 ? -2
: $self->{'rule'}==65 ? -2
: $self->{'rule'}==69 ? -2
: $self->{'rule'}==70 || $self->{'rule'}==198 ? -2
: $self->{'rule'}==77 ? -2
: $self->{'rule'}==78 ? -2
: undef);
}
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1 # is constant dSum=+1
: ($self->{'rule'} & 0x5F) == 0x0E # left line 2
? 3
: $self->{'rule'} == 9 ? 3
: $self->{'rule'}==11 || $self->{'rule'}==43 ? 3
: $self->{'rule'} == 13 ? 2
: $self->{'rule'} == 15 ? 3
: $self->{'rule'}==28 || $self->{'rule'}==156 ? 2
: $self->{'rule'}==47 ? 3
: $self->{'rule'}==77 ? 3
: undef);
}
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? -1
: ($self->{'rule'} & 0x5F) == 0x0E # left line 2
? -1
: ($self->{'rule'} & 0xDF) == 3 # rule=3,35
? -3
: $self->{'rule'} == 5
? -2
: $self->{'rule'} == 7
? -1
: $self->{'rule'} == 9
? -2
: ($self->{'rule'} & 0xDF) == 11 # rule=11,43
? -1
: $self->{'rule'} == 13
? -2
: $self->{'rule'} == 15
? -1
: ($self->{'rule'} & 0xDF) == 17 # rule=17,49
? -3
: $self->{'rule'} == 19
? -2
: $self->{'rule'} == 21
? -1
: ($self->{'rule'} & 0x97) == 23 # rule=23,31,55,63,87,95,119,127
? -1
: $self->{'rule'} == 27
? -2
: $self->{'rule'} == 29
? -2
: undef);
}
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1
: ($self->{'rule'} & 0x5F) == 0x0E # left line 2
? 3
: undef);
}
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
|| ($self->{'rule'} & 0x5F) == 0x0E # left line 2
? 0
: 1); # supremum
}
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1 # N,E only
: 0); # various diagonals
}
sub _NumSeq_Delta_dY_non_decreasing {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
? 1
: 0);
}
use constant _NumSeq_Delta_oeis_anum =>
{
# rule=14,46,142,174 left line 2
do {
my $href
= { dSum => 'A062157', # 0 then 1,-1 repeating
# OEIS-Catalogue: A062157 planepath=CellularRule,rule=14,n_start=0 delta_type=dSum
# OEIS-Other: A062157 planepath=CellularRule,rule=174,n_start=0 delta_type=dSum
};
('rule=14,n_start=0' => $href,
'rule=46,n_start=0' => $href,
'rule=142,n_start=0' => $href,
'rule=174,n_start=0' => $href)
},
# rule=84,116,212,244 right line 2
do {
my $href = { dRSquared => 'A109613', # 1,1,3,3,5,5 odd repeat, OFFSET+0
# OEIS-Catalogue: A109613 planepath=CellularRule,rule=84,n_start=0 delta_type=dRSquared
# OEIS-Other: A109613 planepath=CellularRule,rule=244,n_start=0 delta_type=dRSquared
};
('rule=84,n_start=0' => $href,
'rule=116,n_start=0' => $href,
'rule=212,n_start=0' => $href,
'rule=244,n_start=0' => $href,
)
},
};
}
{ package Math::PlanePath::CellularRule::OneTwo;
use constant _NumSeq_Dir4_max_is_supremum => 0;
use constant _NumSeq_Delta_dSum_non_decreasing => 0;
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
return ($self->{'align'} eq 'left' ? -1 : 1);
}
sub _NumSeq_Delta_dSumAbs_max {
my ($self) = @_;
return ($self->{'align'} eq 'left' ? 3 : 2);
}
use constant _NumSeq_Delta_dAbsDiff_min => -1;
sub _NumSeq_Delta_dAbsDiff_max {
my ($self) = @_;
return ($self->{'align'} eq 'left' ? 3 : 1);
}
use constant _NumSeq_Delta_Dir4_integer => 0;
use constant _NumSeq_Delta_oeis_anum =>
{ 'align=right,n_start=0' =>
{ dSumAbs => 'A177702', # 1,1,2 repeating, OFFSET=0
# OEIS-Catalogue: A177702 planepath=CellularRule,rule=20,n_start=0 delta_type=dSumAbs
},
'align=left,n_start=0' =>
{ AbsdX => 'A177702', # 1,1,2 repeating, OFFSET=0
dSum => 'A102283', # 0,1,-1 repeating, OFFSET=0
dSumAbs => 'A131756', # 2,-1,3 repeating, OFFSET=0
# OEIS-Other: A177702 planepath=CellularRule,rule=6,n_start=0 delta_type=AbsdX
# OEIS-Catalogue: A102283 planepath=CellularRule,rule=6,n_start=0 delta_type=dSum
# OEIS-Catalogue: A131756 planepath=CellularRule,rule=6,n_start=0 delta_type=dSumAbs
},
};
}
{ package Math::PlanePath::CellularRule::Line;
sub _NumSeq_Delta_dSumAbs_min {
my ($self) = @_;
return abs($self->{'sign'}) + 1; # dX=abs(sign),dY=1 always
}
*_NumSeq_Delta_dSumAbs_max = \&_NumSeq_Delta_dSumAbs_min;
# constant left => 2
# centre => 1
# right => 0
sub _NumSeq_Delta_dAbsDiff_min {
my ($self) = @_;
return 1-$self->{'sign'};
}
*_NumSeq_Delta_dAbsDiff_max = \&_NumSeq_Delta_dAbsDiff_min;
sub _NumSeq_Delta_DSquared_min {
my ($path) = @_;
return abs($path->{'sign'}) + 1;
}
*_NumSeq_Delta_DSquared_max = \&_NumSeq_Delta_DSquared_min;
use constant _NumSeq_Dir4_max_is_supremum => 0;
use constant _NumSeq_TDir6_max_is_supremum => 0;
sub _NumSeq_Delta_Dir4_integer {
my ($self) = @_;
return ($self->{'sign'} == 0
? 1 # vertical Dir4=1
: 0); # left,right Dir4=0.5 or 1.5
}
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'sign'} == 0
? 0 # vertical TDir6=1.5
: 1); # left,right Tdir6=1 or 2
}
use constant _NumSeq_Delta_dX_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dY_non_decreasing => 1; # constant
use constant _NumSeq_Delta_AbsdX_non_decreasing => 1; # constant
use constant _NumSeq_Delta_AbsdY_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dSum_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dSumAbs_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dDiffXY_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dDiffYX_non_decreasing => 1; # constant
use constant _NumSeq_Delta_dAbsDiff_non_decreasing => 1; # constant
use constant _NumSeq_Delta_Dir4_non_decreasing => 1; # constant
use constant _NumSeq_Delta_TDir6_non_decreasing => 1; # constant
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDist_non_decreasing => 1;
}
{ package Math::PlanePath::CellularRule::OddSolid;
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_IntXY_min => -1;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # between rows
use constant _NumSeq_Delta_DSquared_min => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # between rows
}
{ package Math::PlanePath::CellularRule54;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # between rows
use constant _NumSeq_Delta_TDir6_integer => 0; # between rows
}
{ package Math::PlanePath::CellularRule57;
use constant _NumSeq_Delta_dAbsDiff_min => -3;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # between rows
use constant _NumSeq_Delta_TDir6_integer => 0; # between rows
}
{ package Math::PlanePath::CellularRule190;
use constant _NumSeq_Delta_dSumAbs_min => -2; # towards Y axis dX=+2
use constant _NumSeq_Delta_dSumAbs_max => 2; # away Y axis dX=+2
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_Dir4_integer => 0; # between rows
use constant _NumSeq_Delta_TDir6_integer => 0; # between rows
}
{ package Math::PlanePath::UlamWarburton;
# minimum dir=0 at N=1
use constant _NumSeq_Delta_DSquared_min => 2; # diagonal
use constant _NumSeq_Delta_TDSquared_min => 4; # diagonal
# always diagonal slope=+/-1 within depth level. parts=2 is horizontal
# between levels, but parts=1 or parts=4 are other slopes between levels.
sub _NumSeq_Delta_TDir6_integer {
my ($self) = @_;
return ($self->{'parts'} eq '2');
}
}
# { package Math::PlanePath::UlamWarburtonQuarter;
# }
{ package Math::PlanePath::CoprimeColumns;
use constant _NumSeq_Delta_TDir6_integer => 0; # between verticals
}
{ package Math::PlanePath::DivisibleColumns;
use constant _NumSeq_Delta_TDir6_integer => 0; # between verticals
}
# { package Math::PlanePath::File;
# # FIXME: analyze points for dx/dy min/max etc
# }
{ package Math::PlanePath::QuintetCurve; # NSEW
# inherit QuintetCentres, except
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::QuintetCentres; # NSEW+diag
use constant _NumSeq_Delta_dSumAbs_min => -2;
use constant _NumSeq_Delta_dSumAbs_max => 2;
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::QuintetReplicate;
# N=1874 Dir4=3.65596
# N=9374 Dir4=3.96738, etc
# Dir4 supremum at 244...44 base 5
use constant _NumSeq_Dir4_max_is_supremum => 1;
use constant _NumSeq_Delta_DSquared_max => 1;
}
{ package Math::PlanePath::AR2W2Curve; # NSEW+diag
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::KochelCurve; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::BetaOmega; # NSEW
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::DekkingCurve; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::DekkingCentres; # NSEW+diag
use constant _NumSeq_Delta_dAbsDiff_min => -2;
use constant _NumSeq_Delta_dAbsDiff_max => 2;
use constant _NumSeq_Delta_TDir6_integer => 0; # verticals
use constant _NumSeq_Delta_DSquared_max => 2;
}
{ package Math::PlanePath::CincoCurve; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::WunderlichMeander; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::HIndexing; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
}
{ package Math::PlanePath::DigitGroups;
use constant _NumSeq_Dir4_max_is_supremum => 1; # almost full way
}
# { package Math::PlanePath::CornerReplicate;
# sub _UNTESTED__NumSeq_Delta_dSum_pred {
# my ($path, $value) = @_;
# # target 1,-1,-3,-7,-15,etc
# # negatives value = -(2^k-1) for k>=1 so -1,-3,-7,-15,etc
# # -value = 2^k-1
# # 1-value = 2^k = 2,4,8,etc
# $value = 1-$value; # 0,2,4,8,16,etc
# if ($value == 0) { return 1; } # original $value=1
# return ($value >= 2 && _is_pow2($value));
# }
# sub _is_pow2 {
# my ($n) = @_;
# my ($pow,$exp) = round_down_pow ($n, 2);
# return ($n == $pow);
# }
# }
{ package Math::PlanePath::SquareReplicate;
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::FibonacciWordFractal; # NSEW
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_DSquared_max => 1; # NSEW only
use constant _NumSeq_Delta_Dist_non_decreasing => 1;
use constant _NumSeq_Delta_TDSquared_max => 3;
use constant _NumSeq_Delta_oeis_anum =>
{ '' =>
{ AbsdX => 'A171587', # diagonal variant
# OEIS-Catalogue: A171587 planepath=FibonacciWordFractal delta_type=AbsdX
},
};
}
{ package Math::PlanePath::LTiling;
use constant _NumSeq_Dir4_max_is_supremum => 1; # almost full way
sub _NumSeq_Delta_DSquared_min {
my ($self) = @_;
return ($self->{'L_fill'} eq 'middle'
? 5 # N=2 dX=2,dY=1
: 1);
}
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'L_fill'} eq 'middle'
? 7 # N=2 dX=2,dY=1
: 1);
}
}
{ package Math::PlanePath::WythoffArray;
use constant _NumSeq_Delta_TDSquared_min => 1;
}
{ package Math::PlanePath::PowerArray;
# at N=1to2 either dX=1,dY=0 if radix=2 or dX=0,dY=1 if radix>2
sub _NumSeq_Delta_TDSquared_min {
my ($self) = @_;
return ($self->{'radix'} == 2
? 1 # dX=1,dY=0
: 3); # dX=0,dY=1
}
use constant _NumSeq_Delta_oeis_anum =>
{ 'radix=2' =>
{
# Not quite, OFFSET=0
# AbsdX => 'A050603', # add1c(n,2)
# # OEIS-Catalogue: A050603 planepath=PowerArray,radix=2 delta_type=AbsdX
# # # Not quite, starts OFFSET=0 (even though A001511 starts OFFSET=1)
# # # vs n_start=1 here
# # dX => 'A094267', # first diffs of count low 0s
# # # OEIS-Catalogue: A094267 planepath=PowerArray,radix=2
#
# # # Not quite, starts OFFSET=0 values 0,1,-1,2 as diffs of A025480
# # # 0,0,1,0,2, vs n_start=1 here doesn't include 0
# # dY => 'A108715', # first diffs of odd part of n
# # # OEIS-Catalogue: A108715 planepath=PowerArray,radix=2 delta_type=dY
},
};
}
{ package Math::PlanePath::ToothpickTree;
{
my %_NumSeq_Dir4_max_is_supremum = (3 => 1,
2 => 1,
1 => 1,
);
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return $_NumSeq_Dir4_max_is_supremum{$self->{'parts'}};
}
}
use constant _NumSeq_Delta_Dir4_integer => 0;
}
{ package Math::PlanePath::ToothpickReplicate;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::ToothpickUpist;
use constant _NumSeq_Delta_Dir4_integer => 0; # diagonal between rows
use constant _NumSeq_Delta_TDir6_integer => 0; # diagonal between rows
}
{ package Math::PlanePath::LCornerTree;
{
my %_NumSeq_Dir4_max_is_supremum
= (4 => 0,
3 => 1,
2 => 1,
1 => 1,
octant => 0,
);
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return $_NumSeq_Dir4_max_is_supremum{$self->{'parts'}};
}
}
use constant _NumSeq_Delta_Dir4_integer => 0;
use constant _NumSeq_Delta_TDir6_integer => 0;
}
{ package Math::PlanePath::ToothpickSpiral;
use constant _NumSeq_Delta_dSumAbs_min => -1;
use constant _NumSeq_Delta_dSumAbs_max => 1;
use constant _NumSeq_Delta_dAbsDiff_min => -1;
use constant _NumSeq_Delta_dAbsDiff_max => 1;
use constant _NumSeq_Delta_oeis_anum =>
{ 'n_start=0' =>
{ AbsdX => 'A000035', # 0,1 repeating
AbsdY => 'A059841', # 1,0 repeating
},
};
}
{ package Math::PlanePath::LCornerReplicate;
use constant _NumSeq_Dir4_max_is_supremum => 1;
}
{ package Math::PlanePath::OneOfEight;
{
my %_NumSeq_Dir4_max_is_supremum
= (4 => 0,
1 => 1,
octant => 0,
'3mid' => 1,
'3side' => 1,
);
sub _NumSeq_Dir4_max_is_supremum {
my ($self) = @_;
return $_NumSeq_Dir4_max_is_supremum{$self->{'parts'}};
}
}
use constant _NumSeq_Delta_Dir4_integer => 0;
use constant _NumSeq_Delta_TDir6_integer => 0;
}
1;
__END__
# sub pred {
# my ($self, $value) = @_;
#
# my $planepath_object = $self->{'planepath_object'};
# my $figure = $planepath_object->figure;
# if ($figure eq 'square') {
# if ($value != int($value)) {
# return 0;
# }
# } elsif ($figure eq 'circle') {
# return 1;
# }
#
# my $delta_type = $self->{'delta_type'};
# if ($delta_type eq 'X') {
# if ($planepath_object->x_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# } elsif ($delta_type eq 'Y') {
# if ($planepath_object->y_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# } elsif ($delta_type eq 'Sum') {
# if ($planepath_object->x_negative || $planepath_object->y_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# }
#
# return undef;
# }
=for stopwords Ryde dX dY dX+dY dX-dY dSum dDiffXY DiffXY dDiffYX dAbsDiff AbsDiff TDir6 Math-NumSeq Math-PlanePath NumSeq SquareSpiral PlanePath AbsdX AbsdY NSEW boolean dSumAbs SumAbs ENWS
=head1 NAME
Math::NumSeq::PlanePathDelta -- sequence of changes and directions of PlanePath coordinates
=head1 SYNOPSIS
use Math::NumSeq::PlanePathDelta;
my $seq = Math::NumSeq::PlanePathDelta->new
(planepath => 'SquareSpiral',
delta_type => 'dX');
my ($i, $value) = $seq->next;
=head1 DESCRIPTION
This is a tie-in to present coordinate changes and directions from a
C module in the form of a NumSeq sequence.
The C choices are
"dX" change in X coordinate
"dY" change in Y coordinate
"AbsdX" abs(dX)
"AbsdY" abs(dY)
"dSum" change in X+Y, equals dX+dY
"dSumAbs" change in abs(X)+abs(Y)
"dDiffXY" change in X-Y, equals dX-dY
"dDiffYX" change in Y-X, equals dY-dX
"dAbsDiff" change in abs(X-Y)
"Dir4" direction 0=East, 1=North, 2=West, 3=South
"TDir6" triangular 0=E, 1=NE, 2=NW, 3=W, 4=SW, 5=SE
In each case the value at i is per C<$path-En_to_dxdy($i)>, being the
change from N=i to N=i+1, or from N=i to N=i+arms for paths with multiple
"arms" (thus following a particular arm). i values start from the usual
C<$path-En_start()>.
=head2 AbsdX,AbsdY
If a path always step NSEW by 1 then AbsdX and AbsdY behave as a boolean
indicating horizontal or vertical step,
NSEW steps by 1
AbsdX = 0 vertical AbsdY = 0 horizontal
1 horizontal 1 vertical
If a path includes diagonal steps by 1 then those diagonals are a non-zero
delta, so the indication is then
NSEW and diagonals steps by 1
AbsdX = 0 vertical AbsdY = 0 horizontal
1 non-vertical 1 non-horizontal
ie. horiz or diag ie. vert or diag
=head2 dSum
"dSum" is the change in X+Y and is also simply dX+dY since
dSum = (Xnext+Ynext) - (X+Y)
= (Xnext-X) + (Ynext-Y)
= dX + dY
The sum X+Y counts anti-diagonals, as described in
L. dSum is therefore a move between diagonals
or 0 if a step stays within the same diagonal.
\
\ ^ dSum > 0 dSum = step dist to North-East
\/
/\
dSum < 0 v \
\
=head2 dSumAbs
"dSumAbs" is the change in the abs(X)+abs(Y) sum,
dSumAbs = (abs(Xnext)+abs(Ynext)) - (abs(X)+abs(Y))
As described in L, SumAbs is a
"taxi-cab" distance from the origin, or equivalently a move between diamond
shaped rings.
As an example, a path such as C follows a diamond shape ring
around and so has dSumAbs=0 until stepping out to the next diamond with
dSumAbs=1.
A path might make a big jump which is only a small change in SumAbs. For
example C in its default step=2 going from the end of one row
to the start of the next has dSumAbs=2.
=head2 dDiffXY and dDiffYX
"dDiffXY" is the change in DiffXY = X-Y, which is also simply dX-dY since
dDiffXY = (Xnext-Ynext) - (X-Y)
= (Xnext-X) - (Ynext-Y)
= dX - dY
The difference X-Y counts diagonals downwards to the south-east as described
in L. dDiffXY is therefore
movement between those diagonals, or 0 if a step stays within the same
diagonal.
dDiffXY < 0 /
\ / dDiffXY = step dist to South-East
\/
/\
/ v
/ dDiffXY > 0
"dDiffYX" is the negative of dDiffXY. Whether X-Y or Y-X is desired depends
on which way you want to measure diagonals, or which way around to have the
sign for the changes. dDiffYX is based on Y-X and so counts diagonals
upwards to the North-West.
=head2 dAbsDiff
"dAbsDiff" is the change in AbsDiff = abs(X-Y). AbsDiff can be interpreted
geometrically as distance from the leading diagonal, as described in
L. dAbsDiff is therefore movement
closer to or further away from that leading diagonal, measured perpendicular
to it.
/ X=Y line
/
/ ^
/ \
/ * dAbsDiff move towards or away from X=Y line
|/ \
--o-- v
/|
/
When an X,Y jumps from one side of the diagonal to the other dAbsDiff is
still the change in distance from the diagonal. So for example if X,Y is
followed by the mirror point Y,X then dAbsDiff=0. That sort of thing
happens for example in the C path when jumping from the end of
one run to the start of the next. In the C case it's a move just
1 further away from the X=Y centre line even though it's a big jump in
overall distance.
=head2 Dir4
"Dir4" is the curve step direction as an angle scaled to range 0 to 4. The
cardinal directions E,N,W,S are 0,1,2,3. Angles in between are a fraction.
Dir4 = atan2(dY,dX) scaled as range 0 <= Dir4 < 4
1.5 1 0.5
\ | /
\|/
2 ----o---- 0
/|\
/ | \
2.5 3 3.5
=head2 TDir6
"TDir6" is the curve step direction in the triangular style of
L. So dX=1,dY=1 is 60 degrees and a
full circle ranges 0 to 6.
2 1.5 1 TDir6
\ | /
\|/
3 ---o--- 0
/|\
/ | \
4 4.5 5
Angles in between the six cardinal directions are fractions. North is 1.5
and South is 4.5.
The direction angle is calculated as if dY was scaled by a factor sqrt(3) to
make the lattice into equilateral triangles, or equivalently as a circle
stretched vertically to become an ellipse.
TDir6 = atan2(dY*sqrt(3), dX) in range 0 <= TDir6 < 6
Notice that angles for dX=0 or dY=0 which are the axes are not changed by
the sqrt(3) factor. So TDir6 has ENWS 0, 1.5, 3, 4.5 which is in steps of
1.5. Verticals North and South normally doesn't occur in the triangular
lattice paths but TDir6 can be applied to other paths.
The sqrt(3) factor increases angles in the middle of the quadrants away from
the axes. For example dX=1,dY=1 becomes TDir6=1 whereas a plain angle would
be only 45/360*6=0.75 in the same 0 to 6 scale. The sqrt(3) is a continuous
scaling, so a plain angle and a TDir6 are a one-to-one mapping. As the
direction progresses through the quadrant TDir6 grows first faster and then
slower than the plain angle.
=head1 FUNCTIONS
See L for behaviour common to all sequence classes.
=over 4
=item C<$seq = Math::NumSeq::PlanePathDelta-Enew (key=Evalue,...)>
Create and return a new sequence object. The options are
planepath string, name of a PlanePath module
planepath_object PlanePath object
delta_type string, as described above
C can be either the module part such as "SquareSpiral" or a
full class name "Math::PlanePath::SquareSpiral".
=item C<$value = $seq-Eith($i)>
Return the change at N=$i in the PlanePath.
=item C<$i = $seq-Ei_start()>
Return the first index C<$i> in the sequence. This is the position
C<$seq-Erewind()> returns to.
This is C<$path-En_start()> from the PlanePath.
=back
=head1 SEE ALSO
L,
L,
L,
L
L
=head1 HOME PAGE
L
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/lib/Math/NumSeq/PlanePathN.pm 0000644 0001750 0001750 00000347627 12252764236 017132 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Maybe:
# "Turn" N of turn positions
# $path->n_next_turn($n)
package Math::NumSeq::PlanePathN;
use 5.004;
use strict;
use Carp;
use constant 1.02;
use vars '$VERSION','@ISA';
$VERSION = 113;
use Math::NumSeq;
@ISA = ('Math::NumSeq');
use Math::NumSeq::PlanePathCoord;
# uncomment this to run the ### lines
# use Smart::Comments;
sub description {
my ($self) = @_;
if (ref $self) {
return "N values on $self->{'line_type'} of path $self->{'planepath'}";
} else {
# class method
return 'N values from a PlanePath';
}
}
use constant::defer parameter_info_array =>
sub {
return [
Math::NumSeq::PlanePathCoord::_parameter_info_planepath(),
{ name => 'line_type',
display => 'Line Type',
type => 'enum',
default => 'X_axis',
choices => ['X_axis',
'Y_axis',
'X_neg',
'Y_neg',
'Diagonal',
'Diagonal_NW',
'Diagonal_SW',
'Diagonal_SE',
'Depth_start',
'Depth_end',
],
description => 'The axis or line to take path N values from.',
},
];
};
#------------------------------------------------------------------------------
my %oeis_anum =
(
# MultipleRings,step=0 -- integers 1,2,3, etc, but starting i=0
);
sub oeis_anum {
my ($self) = @_;
### PlanePathN oeis_anum() ...
my $planepath_object = $self->{'planepath_object'};
{
my $key = Math::NumSeq::PlanePathCoord::_planepath_oeis_anum_key($self->{'planepath_object'});
my $i_start = $self->i_start;
if ($i_start != $self->default_i_start) {
### $i_start
### cf n_start: $planepath_object->n_start
$key .= ",i_start=$i_start";
}
### planepath: ref $planepath_object
### $key
### whole table: $planepath_object->_NumSeq_N_oeis_anum
### key href: $planepath_object->_NumSeq_N_oeis_anum->{$key}
if (my $anum = $planepath_object->_NumSeq_N_oeis_anum->{$key}->{$self->{'line_type'}}) {
return $anum;
}
if (my $anum = $planepath_object->_NumSeq_N_oeis_all_anum->{$self->{'line_type'}}) {
return $anum;
}
}
{
my $key = Math::NumSeq::PlanePathCoord::_planepath_oeis_key($planepath_object);
my $i_start = $self->i_start;
if ($i_start != $self->default_i_start) {
### $i_start
### cf n_start: $planepath_object->n_start
$key .= ",i_start=$i_start";
}
### $key
### hash: $oeis_anum{$key}
return $oeis_anum{$key}->{$self->{'line_type'}};
}
}
#------------------------------------------------------------------------------
sub default_i_start {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'}
# nasty hack allow no 'planepath_object' when SUPER::new() calls rewind()
|| return 0;
my $method = "_NumSeq_$self->{'line_type'}_i_start";
if (my $func = $planepath_object->can($method)) {
return $planepath_object->$func();
}
return 0;
}
sub new {
my $self = shift->SUPER::new(@_);
my $planepath_object = ($self->{'planepath_object'}
||= Math::NumSeq::PlanePathCoord::_planepath_name_to_object($self->{'planepath'}));
### $planepath_object
my $line_type = $self->{'line_type'};
### i_func name: "i_func_$line_type"
$self->{'i_func'}
= $self->can("i_func_$line_type")
|| croak "Unrecognised line_type: ",$line_type;
$self->{'pred_func'}
= $self->can("pred_func_$line_type")
|| croak "Unrecognised line_type: ",$line_type;
if (my $func
= $planepath_object->can("_NumSeq_${line_type}_step")) {
$self->{'i_step'} = $planepath_object->$func();
} elsif ($planepath_object->_NumSeq_A2()
&& ($line_type eq 'X_axis'
|| $line_type eq 'Y_axis'
|| $line_type eq 'X_neg'
|| $line_type eq 'Y_neg')) {
$self->{'i_step'} = 2;
} else {
$self->{'i_step'} = 1;
}
### i_step: $self->{'i_step'}
# for use in pred()
$self->{'i_start'} = $self->i_start;
$self->rewind;
return $self;
}
sub rewind {
my ($self) = @_;
$self->{'i'} = $self->i_start;
}
sub next {
my ($self) = @_;
### NumSeq-PlanePathN next(): "i=$self->{'i'}"
my $i = $self->{'i'};
my $n = &{$self->{'i_func'}} ($self, $i);
### $n
if (! defined $n) {
### i_func returns undef, no value ...
return;
}
# secret experimental automatic bigint to preserve precision
if (! ref $n && $n > 0xFF_FFFF) {
$n = &{$self->{'i_func'}}($self,_to_bigint($i));
}
return ($self->{'i'}++, $n);
}
sub _to_bigint {
my ($n) = @_;
# stringize to avoid UV->BigInt bug in Math::BigInt::GMP version 1.37
return _bigint()->new("$n");
}
# or maybe check for new enough for uv->mpz fix
use constant::defer _bigint => sub {
# Crib note: don't change the back-end if already loaded
unless (Math::BigInt->can('new')) {
require Math::BigInt;
eval { Math::BigInt->import (try => 'GMP') };
}
return 'Math::BigInt';
};
sub ith {
my ($self, $i) = @_;
### NumSeq-PlanePathN ith(): $i
return &{$self->{'i_func'}}($self, $i);
}
sub i_func_X_axis {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n ($i * $self->{'i_step'},
$path_object->_NumSeq_X_axis_at_Y);
}
sub i_func_Y_axis {
my ($self, $i) = @_;
### i_func_Y_axis(): "i=$i"
### X: $self->{'planepath_object'}->_NumSeq_Y_axis_at_X
### Y: $i * $self->{'i_step'}
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n ($path_object->_NumSeq_Y_axis_at_X,
$i * $self->{'i_step'});
}
sub i_func_X_neg {
my ($self, $i) = @_;
### i_func_X_neg(): $i
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n (-$i * $self->{'i_step'},
$path_object->_NumSeq_X_axis_at_Y);
}
sub i_func_Y_neg {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n ($path_object->_NumSeq_Y_axis_at_X,
- $i * $self->{'i_step'});
}
sub i_func_Diagonal {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n ($i + $path_object->_NumSeq_Diagonal_X_offset,
$i);
}
sub i_func_Diagonal_NW {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n (-$i + $path_object->_NumSeq_Diagonal_X_offset,
$i);
}
sub i_func_Diagonal_SW {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n (-$i + $path_object->_NumSeq_Diagonal_X_offset,
-$i);
}
sub i_func_Diagonal_SE {
my ($self, $i) = @_;
my $path_object = $self->{'planepath_object'};
return $path_object->xy_to_n ($i + $path_object->_NumSeq_Diagonal_X_offset,
-$i);
}
sub i_func_Depth_start {
my ($self, $i) = @_;
### i_func_Depth_start(): "i=$i"
return $self->{'planepath_object'}->tree_depth_to_n($i);
}
sub i_func_Depth_end {
my ($self, $i) = @_;
return $self->{'planepath_object'}->tree_depth_to_n_end($i);
}
#------------------------------------------------------------------------------
sub pred {
my ($self, $value) = @_;
### PlanePathN pred(): $value
my $planepath_object = $self->{'planepath_object'};
unless ($value == int($value)) {
return 0;
}
my ($x,$y) = $planepath_object->n_to_xy($value)
or return 0;
return &{$self->{'pred_func'}} ($self, $x,$y, $value);
}
sub pred_func_X_axis {
my ($self, $x,$y) = @_;
return ($x >= $self->{'i_start'}
&& $y == $self->{'planepath_object'}->_NumSeq_X_axis_at_Y);
}
sub pred_func_Y_axis {
my ($self, $x,$y) = @_;
return ($x == $self->{'planepath_object'}->_NumSeq_Y_axis_at_X
&& $y >= $self->{'i_start'});
}
sub pred_func_X_neg {
my ($self, $x,$y) = @_;
return ($x <= - $self->{'i_start'} && $y == 0);
}
sub pred_func_Y_neg {
my ($self, $x,$y) = @_;
return ($x == 0 && $y <= - $self->{'i_start'});
}
sub pred_func_Diagonal {
my ($self, $x,$y) = @_;
$x -= $self->{'planepath_object'}->_NumSeq_Diagonal_X_offset;
return ($x >= $self->{'i_start'} && $x == $y);
}
sub pred_func_Diagonal_NW {
my ($self, $x,$y) = @_;
return ($x <= - $self->{'i_start'} && $x == -$y);
}
sub pred_func_Diagonal_SW {
my ($self, $x,$y) = @_;
return ($x <= - $self->{'i_start'} && $x == $y);
}
sub pred_func_Diagonal_SE {
my ($self, $x,$y) = @_;
return ($x >= $self->{'i_start'} && $x == -$y);
}
sub pred_func_Depth_start {
my ($self, $x,$y, $n) = @_;
return path_tree_n_is_depth_start($self->{'planepath_object'}, $n);
}
sub pred_func_Depth_end {
my ($self, $x,$y, $n) = @_;
return path_tree_n_is_depth_end($self->{'planepath_object'}, $n);
}
# Return true if $n is the start of a depth level.
sub path_tree_n_is_depth_start {
my ($path, $n) = @_;
my $depth = $path->tree_n_to_depth($n);
return (defined $depth && $n == $path->tree_depth_to_n($depth));
}
# Return true if $n is the end of a depth level.
sub path_tree_n_is_depth_end {
my ($path, $n) = @_;
my $depth = $path->tree_n_to_depth($n);
return (defined $depth && $n == $path->tree_depth_to_n_end($depth));
}
#------------------------------------------------------------------------------
use constant characteristic_integer => 1; # integer Ns
sub characteristic_increasing {
my ($self) = @_;
### PlanePathN characteristic_increasing(): $self
my $method = "_NumSeq_$self->{'line_type'}_increasing";
my $planepath_object = $self->{'planepath_object'};
### planepath_object: ref $planepath_object
### $method
### can code: $planepath_object->can($method)
### result: $planepath_object->can($method) && $planepath_object->$method()
return $planepath_object->can($method) && $planepath_object->$method();
}
sub characteristic_increasing_from_i {
my ($self) = @_;
### PlanePathN characteristic_increasing_from_i(): $self
my $planepath_object = $self->{'planepath_object'};
my $method = "_NumSeq_$self->{'line_type'}_increasing_from_i";
### $method
if ($method = $planepath_object->can($method)) {
### can: $method
return $planepath_object->$method();
}
return ($self->characteristic('increasing')
? $self->i_start
: undef);
}
sub characteristic_non_decreasing {
my ($self) = @_;
### PlanePathN characteristic_non_decreasing() ...
my $planepath_object = $self->{'planepath_object'};
my $method = "_NumSeq_$self->{'line_type'}_non_decreasing";
return (($planepath_object->can($method) && $planepath_object->$method())
|| $self->characteristic_increasing);
}
sub values_min {
my ($self) = @_;
### PlanePathN values_min() ...
my $method = "_NumSeq_$self->{'line_type'}_min";
my $planepath_object = $self->{'planepath_object'};
if (my $coderef = $planepath_object->can($method)) {
### $coderef
return $planepath_object->$coderef();
}
return $self->ith($self->i_start);
}
sub values_max {
my ($self) = @_;
my $method = "_NumSeq_$self->{'line_type'}_max";
my $planepath_object = $self->{'planepath_object'};
if (my $coderef = $planepath_object->can($method)) {
return $planepath_object->$coderef();
}
return undef;
}
{ package Math::PlanePath;
sub _NumSeq_X_axis_i_start {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
if (defined $x_minimum && $x_minimum > 0) {
return int($x_minimum);
}
return 0;
}
sub _NumSeq_Y_axis_i_start {
my ($self) = @_;
### _NumSeq_Y_axis_i_start() ...
my $y_minimum = $self->y_minimum;
if (defined $y_minimum && $y_minimum > 0) {
return int($y_minimum);
}
return 0;
}
sub _NumSeq_Y_axis_at_X {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
if (defined $x_minimum && $x_minimum > 0) {
return $x_minimum;
}
return 0;
}
sub _NumSeq_X_axis_at_Y {
my ($self) = @_;
my $y_minimum = $self->y_minimum;
if (defined $y_minimum && $y_minimum > 0) {
return $y_minimum;
}
return 0;
}
# i_start = Xminimum - Xoffset
# gives Xstart = i_start + Xoffset = Xminimum to start at Xminimum
use List::Util;
sub _NumSeq_Diagonal_i_start {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
my $y_minimum = $self->y_minimum;
return List::Util::max
(int(($x_minimum||0) - $self->_NumSeq_Diagonal_X_offset),
int($y_minimum||0),
0);
}
use constant _NumSeq_Diagonal_X_offset => 0;
use constant _NumSeq_N_oeis_anum => {};
use constant _NumSeq_N_oeis_all_anum => {};
use constant _NumSeq_Depth_start_increasing => 1;
use constant _NumSeq_Depth_end_increasing => 1;
# sub _NumSeq_pred_X_axis {
# my ($path, $value) = @_;
# return ($value == int($value)
# && ($path->x_negative || $value >= 0));
# }
# sub _NumSeq_pred_Y_axis {
# my ($path, $value) = @_;
# return ($value == int($value)
# && ($path->y_negative || $value >= 0));
# }
}
{ package Math::PlanePath::SquareSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
sub _NumSeq_X_neg_increasing {
my ($self) = @_;
return ($self->{'wider'} == 0);
}
sub _NumSeq_X_neg_increasing_from_i {
my ($self) = @_;
### SquareSpiral _NumSeq_X_neg_increasing_from_i(): $self
# wider=0 from X=0
# wider=1 from X=-1
# wider=2 from X=-1
return int(($self->{'wider'}+1)/2);
}
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
sub _NumSeq_X_neg_min { # not the value at X=0,Y=0 if wider>0
my ($self) = @_;
return $self->n_start;
}
use constant _NumSeq_N_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ X_axis => 'A054552', # spoke E, 4n^2 - 3n + 1
Y_neg => 'A033951', # spoke S, 4n^2 + 3n + 1
Diagonal_NW => 'A053755', # 4n^2 + 1
Diagonal_SE => 'A016754', # (2n+1)^2
# OEIS-Catalogue: A054552 planepath=SquareSpiral
# OEIS-Catalogue: A033951 planepath=SquareSpiral line_type=Y_neg
# OEIS-Catalogue: A053755 planepath=SquareSpiral line_type=Diagonal_NW
# OEIS-Catalogue: A016754 planepath=SquareSpiral line_type=Diagonal_SE
#
# OEIS-Other: A054552 planepath=GreekKeySpiral,turns=0
# OEIS-Other: A033951 planepath=GreekKeySpiral,turns=0 line_type=Y_neg
# OEIS-Other: A053755 planepath=GreekKeySpiral,turns=0 line_type=Diagonal_NW
# OEIS-Other: A016754 planepath=GreekKeySpiral,turns=0 line_type=Diagonal_SE
# Not quite, these have OFFSET=1 whereas path start X=0
# # Y_axis => 'A054556', # spoke N
# # X_neg => 'A054567', # spoke W
# # Diagonal => 'A054554', # spoke NE
# # Diagonal_SW => 'A054569', # spoke NE
# # # OEIS-Catalogue: A054556 planepath=SquareSpiral line_type=Y_axis
# # # OEIS-Catalogue: A054554 planepath=SquareSpiral line_type=Diagonal
},
'wider=0,n_start=0' =>
{ X_axis => 'A001107',
Y_axis => 'A033991',
Y_neg => 'A033954', # second 10-gonals
Diagonal => 'A002939',
Diagonal_NW => 'A016742', # 10-gonals average, 4*n^2
Diagonal_SW => 'A002943',
# OEIS-Other: A001107 planepath=SquareSpiral,n_start=0 line_type=X_axis
# OEIS-Catalogue: A033991 planepath=SquareSpiral,n_start=0 line_type=Y_axis
# OEIS-Other: A033954 planepath=SquareSpiral,n_start=0 line_type=Y_neg
# OEIS-Catalogue: A002939 planepath=SquareSpiral,n_start=0 line_type=Diagonal
# OEIS-Other: A016742 planepath=SquareSpiral,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A002943 planepath=SquareSpiral,n_start=0 line_type=Diagonal_SW
},
'wider=1,n_start=1' =>
{ Diagonal_SW => 'A069894',
# OEIS-Catalogue: A069894 planepath=SquareSpiral,wider=1 line_type=Diagonal_SW
},
'wider=1,n_start=0' =>
{ Diagonal_SW => 'A016754', # odd squares
# OEIS-Other: A016754 planepath=SquareSpiral,wider=1,n_start=0 line_type=Diagonal_SW
},
};
}
{ package Math::PlanePath::GreekKeySpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
sub _NumSeq_X_neg_increasing {
my ($self) = @_;
return ($self->{'turns'} == 0); # when SquareSpiral style
}
*_NumSeq_Y_neg_increasing = \&_NumSeq_X_neg_increasing;
sub _NumSeq_Diagonal_increasing {
my ($self) = @_;
return ($self->{'turns'} <= 1);
}
sub _NumSeq_Diagonal_NW_increasing {
my ($self) = @_;
return ($self->{'turns'} == 0);
}
*_NumSeq_Diagonal_SW_increasing = \&_NumSeq_Diagonal_increasing;
sub _NumSeq_Diagonal_SE_increasing {
my ($self) = @_;
return ($self->{'turns'} <= 2);
}
use constant _NumSeq_N_oeis_anum =>
{ 'turns=0' =>
(Math::PlanePath::SquareSpiral
->_NumSeq_N_oeis_anum->{'wider=0,n_start=1'}
|| die "Oops, SquareSpiral NumSeq PlanePathN not found"),
};
}
{ package Math::PlanePath::PyramidSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A054552', # square spiral spoke E, 4n^2 - 3n + 1
Diagonal_SE => 'A033951', # square spiral spoke S, 4n^2 + 3n + 1
# OEIS-Other: A054552 planepath=PyramidSpiral
# OEIS-Other: A033951 planepath=PyramidSpiral line_type=Diagonal_SE
},
'n_start=0' =>
{ X_axis => 'A001107', # decagonal
Y_axis => 'A002939',
X_neg => 'A033991',
Y_neg => 'A002943',
Diagonal_SW => 'A007742',
Diagonal_SE => 'A033954', # decagonal second kind
# OEIS-Other: A001107 planepath=PyramidSpiral,n_start=0
# OEIS-Other: A002939 planepath=PyramidSpiral,n_start=0 line_type=Y_axis
# OEIS-Other: A033991 planepath=PyramidSpiral,n_start=0 line_type=X_neg
# OEIS-Other: A002943 planepath=PyramidSpiral,n_start=0 line_type=Y_neg
# OEIS-Other: A007742 planepath=PyramidSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Other: A033954 planepath=PyramidSpiral,n_start=0 line_type=Diagonal_SE
},
'n_start=2' =>
{ Diagonal_SE => 'A185669',
# OEIS-Catalogue: A185669 planepath=PyramidSpiral,n_start=2 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::TriangleSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A117625', # step by 2 each time
Y_neg => 'A006137', # step by 2 each time
Diagonal_SW => 'A064225',
Diagonal_SE => 'A081267',
# OEIS-Other: A117625 planepath=TriangleSpiral line_type=X_axis
# OEIS-Other: A064225 planepath=TriangleSpiral line_type=Diagonal_SW
# OEIS-Other: A081267 planepath=TriangleSpiral line_type=Diagonal_SE
# # Not quite, starts value=3 at n=0 which is path Y=1
# Diagonal => 'A064226', # and duplicate in A081269
},
'n_start=0' =>
{ Y_axis => 'A062741', # 3*pentagonal, Y even
Diagonal => 'A062708', # reading in direction 0,2,...
Diagonal_SW => 'A062725', # reading in direction 0,7,...
Diagonal_SE => 'A062728', # 11-gonal "second" per Math::NumSeq::Polygonal
# OEIS-Catalogue: A062741 planepath=TriangleSpiral,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A062708 planepath=TriangleSpiral,n_start=0 line_type=Diagonal
# OEIS-Catalogue: A062725 planepath=TriangleSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Other: A062728 planepath=TriangleSpiral,n_start=0 line_type=Diagonal_SE
# but spaced 2 apart ...
# X_axis => 'A051682', # 11-gonals per Math::NumSeq::Polygonal
# # OEIS-Other: A051682 planepath=TriangleSpiral,n_start=0 # X_axis
},
};
}
{ package Math::PlanePath::TriangleSpiralSkewed;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# ENHANCE-ME: All these variously rotated for skew=right,up,down
use constant _NumSeq_N_oeis_anum =>
{ 'skew=left,n_start=1' =>
{ X_axis => 'A117625',
X_neg => 'A006137',
Y_neg => 'A064225',
Diagonal => 'A081589',
Diagonal_SW => 'A038764',
Diagonal_SE => 'A081267',
# OEIS-Catalogue: A117625 planepath=TriangleSpiralSkewed
# OEIS-Catalogue: A006137 planepath=TriangleSpiralSkewed line_type=X_neg
# OEIS-Catalogue: A064225 planepath=TriangleSpiralSkewed line_type=Y_neg
# OEIS-Catalogue: A081589 planepath=TriangleSpiralSkewed line_type=Diagonal
# OEIS-Catalogue: A038764 planepath=TriangleSpiralSkewed line_type=Diagonal_SW
# OEIS-Catalogue: A081267 planepath=TriangleSpiralSkewed line_type=Diagonal_SE
# OEIS-Catalogue: A081274 planepath=TriangleSpiralSkewed line_type=Diagonal_SW
# # Not quite, starts OFFSET=0 value=3 but that is at path Y=1
# Y_axis => 'A064226', # and duplicate in A081269
},
'skew=left,n_start=0' =>
{ X_axis => 'A051682', # 11-gonals per Math::NumSeq::Polygonal
Y_axis => 'A062708', # reading in direction 0,2,...
Y_neg => 'A062725', # reading in direction 0,7,...
Diagonal_SE => 'A062728', # 11-gonal "second" per Math::NumSeq::Polygonal
Diagonal_SW => 'A081266',
# OEIS-Other: A051682 planepath=TriangleSpiralSkewed,n_start=0 # X_axis
# OEIS-Other: A062708 planepath=TriangleSpiralSkewed,n_start=0 line_type=Y_axis
# OEIS-Other: A062725 planepath=TriangleSpiralSkewed,n_start=0 line_type=Y_neg
# OEIS-Other: A062728 planepath=TriangleSpiralSkewed,n_start=0 line_type=Diagonal_SE
# OEIS-Catalogue: A081266 planepath=TriangleSpiralSkewed,n_start=0 line_type=Diagonal_SW
},
};
}
{ package Math::PlanePath::DiamondSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A130883', # 2*n^2-n+1
X_neg => 'A084849', # 2*n^2+n+1
Y_axis => 'A058331', # 2*n^2 + 1
Y_neg => 'A001844', # centred squares 2n(n+1)+1
# OEIS-Catalogue: A130883 planepath=DiamondSpiral
# OEIS-Other: A084849 planepath=DiamondSpiral line_type=X_neg
# OEIS-Catalogue: A058331 planepath=DiamondSpiral line_type=Y_axis
# OEIS-Other: A001844 planepath=DiamondSpiral line_type=Y_neg
},
'n_start=0' =>
{ X_axis => 'A000384', # 2*n^2-n, hexagonal numbers
X_neg => 'A014105', # 2*n^2+n, hexagonal numbers second kind
Y_axis => 'A001105', # 2*n^2
Y_neg => 'A046092', # 2n(n+1) = 4*triangular
# OEIS-Other: A000384 planepath=DiamondSpiral,n_start=0
# OEIS-Other: A014105 planepath=DiamondSpiral,n_start=0 line_type=X_neg
# OEIS-Other: A001105 planepath=DiamondSpiral,n_start=0 line_type=Y_axis
# OEIS-Other: A046092 planepath=DiamondSpiral,n_start=0 line_type=Y_neg
},
};
}
{ package Math::PlanePath::DiamondArms;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::AztecDiamondRings;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A001844', # centred squares 2n(n+1)+1
# OEIS-Other: A001844 planepath=AztecDiamondRings
# Not quite, A000384 has extra value=0
# Y_axis => 'A000384', # hexagonal numbers
},
};
}
{ package Math::PlanePath::PentSpiral;
use constant _NumSeq_X_axis_step => 2;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A192136', # (5*n^2-3*n+2)/2
X_neg => 'A116668', # (5n^2 + n + 2)/2
Diagonal_SE => 'A005891', # centred pentagonal (5n^2+5n+2)/2
# OEIS-Other: A192136 planepath=PentSpiral
# OEIS-Other: A116668 planepath=PentSpiral line_type=X_neg
# OEIS-Other: A005891 planepath=PentSpiral line_type=Diagonal_SE
# Not quite, A134238 OFFSET=1 vs start X=0 here
# Diagonal_SW => 'A134238',
},
'n_start=0' =>
{ X_axis => 'A000566', # heptagonals
Y_axis => 'A005476',
Diagonal_SE => 'A028895', # 5*triangular
# OEIS-Other: A000566 planepath=PentSpiral,n_start=0
# OEIS-Other: A005476 planepath=PentSpiral,n_start=0 line_type=Y_axis
# OEIS-Other: A028895 planepath=PentSpiral,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::PentSpiralSkewed;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_axis => 'A192136', # (5*n^2-3*n+2)/2
X_neg => 'A116668', # (5n^2 + n + 2)/2
Diagonal_NW => 'A158187', # 10*n^2 + 1
Diagonal_SE => 'A005891', # centred pentagonal (5n^2+5n+2)/2
# OEIS-Catalogue: A192136 planepath=PentSpiralSkewed
# OEIS-Catalogue: A116668 planepath=PentSpiralSkewed line_type=X_neg
# OEIS-Catalogue: A158187 planepath=PentSpiralSkewed line_type=Diagonal_NW
# OEIS-Catalogue: A005891 planepath=PentSpiralSkewed line_type=Diagonal_SE
# Not quite, A140066 OFFSET=1 but path start Y=0 here
# Y_axis => 'A140066', # (5n^2-11n+8)/2 but from Y=0 so using (n-1)
# Not quite, A134238 OFFSET=1 but path start Y=0 here
# Y_neg => 'A134238',
# # OEIS-Catalogue: A134238 planepath=PentSpiralSkewed line_type=Y_neg
},
'n_start=0' =>
{ X_axis => 'A000566', # heptagonals
Y_axis => 'A005476',
X_neg => 'A005475',
Diagonal_NW => 'A033583', # 10*n^2
Diagonal_SE => 'A028895', # 5*triangular
# OEIS-Other: A000566 planepath=PentSpiralSkewed,n_start=0
# OEIS-Catalogue: A005476 planepath=PentSpiralSkewed,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A005475 planepath=PentSpiralSkewed,n_start=0 line_type=X_neg
# OEIS-Other: A033583 planepath=PentSpiralSkewed,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A028895 planepath=PentSpiralSkewed,n_start=0 line_type=Diagonal_SE
# Not quite, A147875 OFFSET=1 vs start Y=0 here
# Y_neg => 'A147875', # second heptagonals
# # OEIS-Other: A147875 planepath=PentSpiralSkewed,n_start=0 line_type=Y_neg
},
};
}
{ package Math::PlanePath::HexSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
*_NumSeq_X_neg_increasing
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing;
*_NumSeq_X_neg_increasing_from_i
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing_from_i;
*_NumSeq_X_neg_min
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_min;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ X_axis => 'A056105', # first spoke 3n^2-2n+1
Diagonal => 'A056106', # second spoke 3n^2-n+1
Diagonal_NW => 'A056107', # third spoke 3n^2+1
X_neg => 'A056108', # fourth spoke 3n^2+n+1
Diagonal_SW => 'A056109', # fifth spoke 3n^2+2n+1
Diagonal_SE => 'A003215', # centred hexagonal numbers
# OEIS-Other: A056105 planepath=HexSpiral
# OEIS-Other: A056106 planepath=HexSpiral line_type=Diagonal
# OEIS-Other: A056107 planepath=HexSpiral line_type=Diagonal_NW
# OEIS-Other: A056108 planepath=HexSpiral line_type=X_neg
# OEIS-Other: A056109 planepath=HexSpiral line_type=Diagonal_SW
# OEIS-Other: A003215 planepath=HexSpiral line_type=Diagonal_SE
},
'wider=0,n_start=0' =>
{ X_axis => 'A000567', # octagonal numbers
X_neg => 'A049451',
Diagonal => 'A049450',
Diagonal_NW => 'A033428', # octagonal numbers first,second average
Diagonal_SW => 'A045944', # octagonal numbers second
Diagonal_SE => 'A028896',
# OEIS-Other: A000567 planepath=HexSpiral,n_start=0 line_type=X_axis
# OEIS-Other: A049451 planepath=HexSpiral,n_start=0 line_type=X_neg
# OEIS-Catalogue: A049450 planepath=HexSpiral,n_start=0 line_type=Diagonal
# OEIS-Other: A033428 planepath=HexSpiral,n_start=0 line_type=Diagonal_NW
# OEIS-Other: A045944 planepath=HexSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Catalogue: A028896 planepath=HexSpiral,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::HexSpiralSkewed;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
*_NumSeq_X_neg_increasing
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing;
*_NumSeq_X_neg_increasing_from_i
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing_from_i;
*_NumSeq_X_neg_min
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_min;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ X_axis => 'A056105', # first spoke 3n^2-2n+1
Y_axis => 'A056106', # second spoke 3n^2-n+1
Diagonal_NW => 'A056107', # third spoke 3n^2+1
X_neg => 'A056108', # fourth spoke 3n^2+n+1
Y_neg => 'A056109', # fifth spoke 3n^2+2n+1
Diagonal_SE => 'A003215', # centred hexagonal numbers
# OEIS-Catalogue: A056105 planepath=HexSpiralSkewed
# OEIS-Catalogue: A056106 planepath=HexSpiralSkewed line_type=Y_axis
# OEIS-Catalogue: A056108 planepath=HexSpiralSkewed line_type=X_neg
# OEIS-Catalogue: A056109 planepath=HexSpiralSkewed line_type=Y_neg
# OEIS-Catalogue: A056107 planepath=HexSpiralSkewed line_type=Diagonal_NW
# OEIS-Other: A003215 planepath=HexSpiralSkewed line_type=Diagonal_SE
},
'wider=0,n_start=0' =>
{ X_axis => 'A000567', # octagonal numbers
Y_axis => 'A049450',
X_neg => 'A049451',
Y_neg => 'A045944', # octagonal numbers second
Diagonal => 'A062783',
Diagonal_NW => 'A033428', # octagonal numbers first,second average
Diagonal_SW => 'A063436',
Diagonal_SE => 'A028896',
# OEIS-Other: A000567 planepath=HexSpiralSkewed,n_start=0 line_type=X_axis
# OEIS-Other: A049450 planepath=HexSpiralSkewed,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A049451 planepath=HexSpiralSkewed,n_start=0 line_type=X_neg
# OEIS-Other: A045944 planepath=HexSpiralSkewed,n_start=0 line_type=Y_neg
# OEIS-Catalogue: A062783 planepath=HexSpiralSkewed,n_start=0 line_type=Diagonal
# OEIS-Other: A033428 planepath=HexSpiralSkewed,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A063436 planepath=HexSpiralSkewed,n_start=0 line_type=Diagonal_SW
# OEIS-Other: A028896 planepath=HexSpiralSkewed,n_start=0 line_type=Diagonal_SE
},
# wider=1 X_axis almost 3*n^2 but not initial X=0 value
# wider=1 Y_axis almost A049451 twice pentagonal but not initial X=0
# wider=2 Y_axis almost A028896 6*triangular but not initial Y=0
};
}
{ package Math::PlanePath::HexArms;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::HeptSpiralSkewed;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
# 'n_start=1' =>
# {
# # Not quite, OFFSET=1 vs path start X=Y=0
# # Y_axis => 'A140065', # (7n^2 - 17n + 12)/2 but starting Y=0 not n=1
# # Diagonal_NW => 'A140063',
# # Diagonal_SE => 'A069099',
# },
'n_start=0' =>
{ X_axis => 'A001106', # 9-gonals
X_neg => 'A022265',
Y_neg => 'A179986', # second 9-gonals
Diagonal => 'A195023',
Diagonal_NW => 'A022264',
Diagonal_SW => 'A186029',
Diagonal_SE => 'A024966',
# OEIS-Other: A001106 planepath=HeptSpiralSkewed,n_start=0
# OEIS-Catalogue: A022265 planepath=HeptSpiralSkewed,n_start=0 line_type=X_neg
# OEIS-Other: A179986 planepath=HeptSpiralSkewed,n_start=0 line_type=Y_neg
# OEIS-Catalogue: A195023 planepath=HeptSpiralSkewed,n_start=0 line_type=Diagonal
# OEIS-Catalogue: A022264 planepath=HeptSpiralSkewed,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A186029 planepath=HeptSpiralSkewed,n_start=0 line_type=Diagonal_SW
# OEIS-Catalogue: A024966 planepath=HeptSpiralSkewed,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::OctagramSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
'n_start=1' =>
{ Diagonal_SE => 'A194268',
# OEIS-Other: A194268 planepath=OctagramSpiral line_type=Diagonal_SE
# Not quite, but A125201 doesn't have initial N=1 for path origin
# X_axis => 'A125201'
},
'n_start=0' =>
{ X_axis => 'A051870', # 18-gonals
Y_axis => 'A139273',
X_neg => 'A139275',
Y_neg => 'A139277',
Diagonal => 'A139272',
Diagonal_NW => 'A139274',
Diagonal_SW => 'A139276',
Diagonal_SE => 'A139278', # second 18-gonals
# OEIS-Other: A051870 planepath=OctagramSpiral,n_start=0
# OEIS-Catalogue: A139273 planepath=OctagramSpiral,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A139275 planepath=OctagramSpiral,n_start=0 line_type=X_neg
# OEIS-Catalogue: A139277 planepath=OctagramSpiral,n_start=0 line_type=Y_neg
# OEIS-Catalogue: A139272 planepath=OctagramSpiral,n_start=0 line_type=Diagonal
# OEIS-Catalogue: A139274 planepath=OctagramSpiral,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A139276 planepath=OctagramSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Other: A139278 planepath=OctagramSpiral,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::AnvilSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
*_NumSeq_X_neg_increasing
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing;
*_NumSeq_X_neg_increasing_from_i
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_increasing_from_i;
*_NumSeq_X_neg_min
= \&Math::PlanePath::SquareSpiral::_NumSeq_X_neg_min;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ X_axis => 'A033570', # odd pentagonals (2n+1)*(3n+1)
Diagonal => 'A033568', # odd second pentagonals
Diagonal_SE => 'A085473',
# OEIS-Catalogue: A033570 planepath=AnvilSpiral
# OEIS-Catalogue: A033568 planepath=AnvilSpiral line_type=Diagonal
# OEIS-Catalogue: A085473 planepath=AnvilSpiral line_type=Diagonal_SE
# Not quite, A136392 OFFSET=1 value=1 whereas path start Y=0 value=1
# Y_neg => 'A136392', # 1,9,29,61, 6n^2-10n+5
},
'wider=0,n_start=1,i_start=1' =>
{ Y_axis => 'A126587', # points within 3,4,5 triangle, starting value=3
# OEIS-Catalogue: A126587 planepath=AnvilSpiral line_type=Y_axis i_start=1
},
# 'wider=2,n_start=1' =>
# {
# Not quite, A033581 initial value=2 whereas path start N=0
# # Y_axis => 'A033581', # 6*n^2 is 14-gonals pairs average in Math::NumSeq::Polygonal
# # # OEIS-Other: A033581 planepath=AnvilSpiral,wider=2 line_type=Y_axis
# },
'wider=0,n_start=0' =>
{ X_axis => 'A211014', # 14-gonal second
Y_axis => 'A139267', # 2*octagonal
X_neg => 'A049452', # alternate pentagonals
Y_neg => 'A033580', # 4*second pentagonals
Diagonal => 'A051866', # 14-gonals
Diagonal_NW => 'A094159', # 3*hexagonal
Diagonal_SW => 'A049453',
Diagonal_SE => 'A195319', # 3*second hexagonal
# OEIS-Other: A211014 planepath=AnvilSpiral,n_start=0
# OEIS-Other: A051866 planepath=AnvilSpiral,n_start=0 line_type=Diagonal
# OEIS-Catalogue: A139267 planepath=AnvilSpiral,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A049452 planepath=AnvilSpiral,n_start=0 line_type=X_neg
# OEIS-Catalogue: A033580 planepath=AnvilSpiral,n_start=0 line_type=Y_neg
# OEIS-Catalogue: A094159 planepath=AnvilSpiral,n_start=0 line_type=Diagonal_NW
# OEIS-Catalogue: A049453 planepath=AnvilSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Catalogue: A195319 planepath=AnvilSpiral,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::KnightSpiral;
use constant _NumSeq_Diagonal_increasing => 1; # low then high
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::CretanLabyrinth;
use constant _NumSeq_X_axis_increasing => 1;
}
{ package Math::PlanePath::SquareArms;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::SacksSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# SacksSpiral X_axis -- squares (i-1)^2, starting from i=1 value=0
}
{ package Math::PlanePath::VogelFloret;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::TheodorusSpiral;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::ArchimedeanChords;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::MultipleRings;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::PixelRings;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # where covered
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::FilledRings;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# use constant _NumSeq_N_oeis_anum =>
# {
# # Not quite, A036704 OFFSET=0 value=1,9,21 vs X=0 value=0,1,9,21
# 'n_start=0' =>
# { X_axis => 'A036704', # count points norm <= n+1/2
# },
# };
}
{ package Math::PlanePath::Hypot;
sub _NumSeq_X_axis_i_start {
my ($self) = @_;
### _NumSeq_X_axis_i_start() ...
return ($self->{'points'} eq 'odd'
? 1 # X=0,Y=0 not visited
: 0);
}
sub _NumSeq_X_neg_i_start {
my ($self) = @_;
### _NumSeq_X_axis_i_start() ...
return ($self->{'points'} eq 'odd'
? -1 # X=0,Y=0 not visited
: 0);
}
*_NumSeq_Y_axis_i_start = \&_NumSeq_X_axis_i_start;
*_NumSeq_Y_neg_i_start = \&_NumSeq_X_neg_i_start;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'points=all,n_start=0' =>
{ X_axis => 'A051132', # count points < n^2
# OEIS-Catalogue: A051132 planepath=Hypot,n_start=0
},
};
}
{ package Math::PlanePath::HypotOctant;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
*_NumSeq_X_axis_i_start = \&Math::PlanePath::Hypot::_NumSeq_X_axis_i_start;
use constant _NumSeq_N_oeis_anum =>
{ 'points=even' =>
{ Diagonal => 'A036702', # count points |z|<=n for 0<=b<=a
# OEIS-Catalogue: A036702 planepath=HypotOctant,points=even line_type=Diagonal
},
};
}
{ package Math::PlanePath::TriangularHypot;
sub _NumSeq_X_axis_i_start {
my ($self) = @_;
return ($self->{'points'} eq 'odd' || $self->{'points'} eq 'hex_centred'
? 1 # X=0,Y=0 not visited
: 0);
}
*_NumSeq_Diagonal_i_start = \&_NumSeq_X_axis_i_start;
*_NumSeq_Diagonal_SE_i_start = \&_NumSeq_X_axis_i_start;
sub _NumSeq_X_neg_i_start {
my ($self) = @_;
return - $self->_NumSeq_X_axis_i_start;
}
*_NumSeq_Diagonal_NW_i_start = \&_NumSeq_X_axis_i_start;
*_NumSeq_Diagonal_SW_i_start = \&_NumSeq_X_axis_i_start;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::PythagoreanTree;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_N_oeis_all_anum =>
{ Depth_start => 'A007051', # (3^n+1)/2
# OEIS-Catalogue: A007051 planepath=PythagoreanTree line_type=Depth_start
# Not quite, Depth_end=(3^(n+1)-1)/2, so is n+1
# Depth_end => 'A003462', # (3^n-1)/2
};
}
{ package Math::PlanePath::RationalsTree;
use constant _NumSeq_X_axis_increasing => 1;
sub _NumSeq_Y_axis_increasing {
my ($self) = @_;
return ($self->{'tree_type'} eq 'L' ? 0 : 1);
}
sub _NumSeq_Y_axis_increasing_from_i {
my ($self) = @_;
return ($self->{'tree_type'} eq 'L' ? 2 : 1);
}
use constant _NumSeq_Y_axis_min => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'tree_type=SB' =>
{ Depth_start => 'A000079', # powers-of-2
# RationalsTree SB -- X_axis 2^n-1 but starting X=1
# RationalsTree SB,CW -- Y_axis A000079 2^n but starting Y=1
},
'tree_type=CW' =>
{ Depth_start => 'A000079', # powers-of-2
},
'tree_type=Bird' =>
{ X_axis => 'A081254', # local max sumdisttopow2(m)/m^2
Depth_start => 'A000079', # powers-of-2
# OEIS-Catalogue: A081254 planepath=RationalsTree,tree_type=Bird
# OEIS-Other: A000079 planepath=RationalsTree,tree_type=Bird line_type=Depth_start
# RationalsTree Bird -- Y_axis almost A000975 10101 101010 no
# consecutive equal bits, but start=1
},
'tree_type=Drib' =>
{ X_axis => 'A086893', # pos of fibonacci F(n+1)/F(n) in Stern diatomic
Depth_start => 'A000079', # powers-of-2
# OEIS-Catalogue: A086893 planepath=RationalsTree,tree_type=Drib
# Drib Y_axis
# Not quite, A061547 OFFSET=1 value=0 cf path Y=1 value N=1
# Y_axis => 'A061547'# derangements or alternating bits plus pow4
},
'tree_type=AYT' =>
{ Depth_start => 'A000079', # powers-of-2
# RationalsTree AYT -- Y_axis A083318 2^n+1 but starting Y=1
},
'tree_type=HCS' =>
{ Depth_start => 'A000079', # powers-of-2
# RationalsTree HCS
# Not quite, A000079 OFFSET=0 value=1 cf here X=1 N=1
# X_axis => 'A000079', # powers 2^X
# Not quite, A007283 OFFSET=0 and doesn't have extra N=1 at Y=1
# Y_axis => 'A007283', # 3*2^n starting OFFSET=0 value=3
},
};
}
{ package Math::PlanePath::FractionsTree;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_X_offset => -1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Y_axis_i_start => 2;
}
{ package Math::PlanePath::ChanTree;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_X_axis_i_start => 1;
use constant _NumSeq_Y_axis_i_start => 1; # start at Y=1
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'k=2,n_start=1' =>
{ Depth_start => 'A000079', # powers-of-2
# OEIS-Other: A000079 planepath=ChanTree,n_start=1,k=2 line_type=Depth_start
# Depth_end is 2^k-1 A000225, or 2^k-2 A000918, but without initial
# 0 or -1.
},
'k=2,n_start=0' =>
{ Depth_start => 'A000225', # 2^k-1
# OEIS-Other: A000225 planepath=ChanTree,k=2 line_type=Depth_start
},
'k=3,n_start=1' =>
{ Depth_start => 'A000244', # powers-of-3
# OEIS-Other: A000244 planepath=ChanTree,n_start=1 line_type=Depth_start
},
'k=4,n_start=1' =>
{ Depth_start => 'A000302', # powers-of-4
# OEIS-Other: A000302 planepath=ChanTree,n_start=1,k=4 line_type=Depth_start
},
'k=5,n_start=1' =>
{ Depth_start => 'A000351', # powers-of-5
# OEIS-Other: A000351 planepath=ChanTree,n_start=1,k=5 line_type=Depth_start
},
'k=10,n_start=1' =>
{ Depth_start => 'A011557', # powers-of-10
# OEIS-Other: A011557 planepath=ChanTree,n_start=1,k=10 line_type=Depth_start
},
};
}
{ package Math::PlanePath::DiagonalRationals;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_axis_i_start => 1;
use constant _NumSeq_Y_axis_i_start => 1;
# Diagonal => 'A002088', # cumulative totient
# Not quite, start X=1 value=1 cf seq OFFSET=0 value=0
}
{ package Math::PlanePath::FactorRationals;
use constant _NumSeq_X_axis_i_start => 1;
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
# perfect squares along X axis of even/odd
return $self->{'factor_coding'} eq 'even/odd';
}
use constant _NumSeq_Y_axis_i_start => 1;
sub _NumSeq_Y_axis_increasing {
my ($self) = @_;
# perfect squares along Y axis of odd/even
return $self->{'factor_coding'} eq 'odd/even';
}
use constant _NumSeq_N_oeis_anum =>
{ 'factor_coding=even/odd' =>
{ Y_axis => 'A102631', # n^2/(squarefree kernel)
# OEIS-Catalogue: A102631 planepath=FactorRationals line_type=Y_axis
# # Not quite, OFFSET=0 value 0 whereas start X=Y=1 value 1 here
# X_axis => 'A000290', # squares 0,1,4,9
# # OEIS-Other: A000290 planepath=FactorRationals line_type=X_axis
},
'factor_coding=odd/even' =>
{ X_axis => 'A102631', # n^2/(squarefree kernel)
# OEIS-Other: A102631 planepath=FactorRationals,factor_coding=odd/even line_type=X_axis
},
};
}
{ package Math::PlanePath::GcdRationals;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_axis_i_start => 1;
use constant _NumSeq_Y_axis_i_start => 1;
# GcdRationals
# Not quite, starts X=1
# X_axis => triangular row
# Not quite, starts X=1 here cf OFFSET=0 in A000124
# Y_axis => 'A000124', # triangular+1
#
# GcdRationals,pairs_order=diagonals_down
# Not quite, start X=1 here cf A000290 starts OFFSET=1
# X_axis => 'A000290', # Y=1 row, perfect squares
# Not quite, A033638 starts two ones 1,1,...
# Y_axis => 'A033638', # quarter-squares + 1
#
# GcdRationals,pairs_order=diagonals_up
# Not quite, A002061 starts two ones 1,1,
# X_axis => 'A002061',
# Not quite, X=1 column squares+pronic, but no initial 0,0 of A002620
# Y_axis => 'A002620', # X=1 column
# Not quite, starting value=2 here
# Diagonal_above => 'A002522', # Y=X+1 diagonal, squares+1
}
{ package Math::PlanePath::CfracDigits;
# 1
# diagonal Y/(Y+1) = 0 + -----
# 1 + 1/Y
# q0=1 q1=Y
# N = 3,Y-1 in 1,2,3
# = 1,0,Y-1 in 0,1,2
#
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_X_offset => -1;
use constant _NumSeq_Y_axis_increasing => 1; # radix without digit 0
}
{ package Math::PlanePath::PeanoCurve;
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
return ($self->{'radix'} % 2);
}
*_NumSeq_Y_axis_increasing = \&_NumSeq_X_axis_increasing;
use constant _NumSeq_N_oeis_anum =>
{ 'radix=3' =>
{ X_axis => 'A163480', # axis same as initial direction
Y_axis => 'A163481', # axis opp to initial direction
Diagonal => 'A163343',
},
# OEIS-Catalogue: A163480 planepath=PeanoCurve
# OEIS-Catalogue: A163481 planepath=PeanoCurve line_type=Y_axis
# OEIS-Catalogue: A163343 planepath=PeanoCurve line_type=Diagonal
# OEIS-Other: A163480 planepath=GrayCode,apply_type=TsF,radix=3
# OEIS-Other: A163481 planepath=GrayCode,apply_type=TsF,radix=3 line_type=Y_axis
# OEIS-Other: A163343 planepath=GrayCode,apply_type=TsF,radix=3 line_type=Diagonal
# OEIS-Other: A163480 planepath=GrayCode,apply_type=FsT,radix=3
# OEIS-Other: A163481 planepath=GrayCode,apply_type=FsT,radix=3 line_type=Y_axis
# OEIS-Other: A163343 planepath=GrayCode,apply_type=FsT,radix=3 line_type=Diagonal
};
}
{ package Math::PlanePath::WunderlichSerpentine;
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
if ($self->{'radix'} % 2) {
return 1; # odd radix always increasing
}
# FIXME: depends on the serpentine_type bits
return 0;
}
sub _NumSeq_Y_axis_increasing {
my ($self) = @_;
if ($self->{'radix'} % 2) {
return 1; # odd radix always increasing
}
# FIXME: depends on the serpentine_type bits
return 0;
}
}
{ package Math::PlanePath::HilbertCurve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ '' =>
{ X_axis => 'A163482',
Y_axis => 'A163483',
Diagonal => 'A062880', # base 4 digits 0,2 only
# OEIS-Catalogue: A163482 planepath=HilbertCurve
# OEIS-Catalogue: A163483 planepath=HilbertCurve line_type=Y_axis
# OEIS-Other: A062880 planepath=HilbertCurve line_type=Diagonal
},
};
}
{ package Math::PlanePath::HilbertSpiral;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
}
{ package Math::PlanePath::ZOrderCurve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'radix=2' =>
{ X_axis => 'A000695', # base 4 digits 0,1 only (RadixConversion)
Y_axis => 'A062880', # base 4 digits 0,2 only
Diagonal => 'A001196', # base 4 digits 0,3 only
# OEIS-Other: A000695 planepath=ZOrderCurve
# OEIS-Catalogue: A062880 planepath=ZOrderCurve line_type=Y_axis
# OEIS-Catalogue: A001196 planepath=ZOrderCurve line_type=Diagonal
},
'radix=3,i_start=1' =>
{ X_axis => 'A037314', # base 9 digits 0,1,2 only
# OEIS-Catalogue: A037314 planepath=ZOrderCurve,radix=3 i_start=1
# A037314 starts OFFSET=1 value=1, hence i_start=1 here
},
'radix=10' =>
{ X_axis => 'A051022', # base 10 insert 0s, for digits 0 to 9 base 100
# OEIS-Catalogue: A051022 planepath=ZOrderCurve,radix=10
},
};
}
{ package Math::PlanePath::GrayCode;
# X axis increasing for:
# radix=2 TsF,Fs
# radix=3 reflected TsF,FsT
# radix=3 modular TsF,Fs
# radix=4 reflected TsF,Fs
# radix=4 modular TsF,Fs
# radix=5 reflected TsF,FsT
# radix=5 modular TsF,Fs
#
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
if ($self->{'gray_type'} eq 'modular' || $self->{'radix'} == 2) {
return ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'Fs');
}
if ($self->{'radix'} & 1) {
return ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'FsT');
} else {
return ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'Fs');
}
}
*_NumSeq_Y_axis_increasing = \&_NumSeq_X_axis_increasing;
# Diagonal increasing for:
# radix=2 FsT,Ts
# radix=3 reflected Ts,Fs
# radix=3 modular FsT
# radix=4 reflected FsT,Ts
# radix=4 modular FsT
# radix=5 reflected Ts,Fs
# radix=5 modular FsT
sub _NumSeq_Diagonal_increasing {
my ($self) = @_;
if ($self->{'radix'} & 1) {
if ($self->{'gray_type'} eq 'modular') {
return ($self->{'apply_type'} eq 'FsT'); # odd modular
} else {
return ($self->{'apply_type'} eq 'Ts'
|| $self->{'apply_type'} eq 'Fs'); # odd reflected
}
}
if ($self->{'gray_type'} eq 'reflected' || $self->{'radix'} == 2) {
return ($self->{'apply_type'} eq 'FsT'
|| $self->{'apply_type'} eq 'Ts'); # even reflected
} else {
return ($self->{'apply_type'} eq 'FsT'); # even modular
}
}
use constant _NumSeq_N_oeis_anum =>
{
'apply_type=TsF,gray_type=reflected,radix=3' =>
(Math::PlanePath::PeanoCurve->_NumSeq_N_oeis_anum->{'radix=3'}
|| die "Oops, SquareSpiral NumSeq PlanePathN not found"),
'apply_type=FsT,gray_type=reflected,radix=3' =>
(Math::PlanePath::PeanoCurve->_NumSeq_N_oeis_anum->{'radix=3'}
|| die "Oops, SquareSpiral NumSeq PlanePathN not found"),
# GrayCode radix=2 TsF==Fs reflected==modular
do {
my $href =
{ Y_axis => 'A001196', # base 4 digits 0,3 only
};
('apply_type=TsF,gray_type=reflected,radix=2' => $href,
'apply_type=Fs,gray_type=reflected,radix=2' => $href,
'apply_type=TsF,gray_type=modular,radix=2' => $href,
'apply_type=Fs,gray_type=modular,radix=2' => $href,
);
# OEIS-Other: A001196 planepath=GrayCode,apply_type=TsF line_type=Y_axis
# OEIS-Other: A001196 planepath=GrayCode,apply_type=Fs line_type=Y_axis
# OEIS-Other: A001196 planepath=GrayCode,apply_type=TsF,gray_type=modular line_type=Y_axis
# OEIS-Other: A001196 planepath=GrayCode,apply_type=Fs,gray_type=modular line_type=Y_axis
},
# GrayCode radix=2 Ts==FsT reflected==modular
do {
my $href =
{ Diagonal => 'A062880', # base 4 digits 0,2 only
};
('apply_type=Ts,gray_type=reflected,radix=2' => $href,
'apply_type=Ts,gray_type=modular,radix=2' => $href,
'apply_type=FsT,gray_type=reflected,radix=2' => $href,
'apply_type=FsT,gray_type=modular,radix=2' => $href,
);
# OEIS-Other: A062880 planepath=GrayCode,apply_type=Ts line_type=Diagonal
# OEIS-Other: A062880 planepath=GrayCode,apply_type=Ts,gray_type=modular line_type=Diagonal
# OEIS-Other: A062880 planepath=GrayCode,apply_type=FsT line_type=Diagonal
# OEIS-Other: A062880 planepath=GrayCode,apply_type=FsT,gray_type=modular line_type=Diagonal
},
# GrayCode radix=3 sT==sF reflected
# N split then toGray giving Y=0 means N ternary 010202 etc
# N split then toGray giving X=Y means N ternary pairs 112200
do {
my $href =
{ X_axis => 'A163344', # central Peano/4, base9 digits 0,1,2 only
Diagonal => 'A163343', # central diagonal of Peano, base9 0,4,8
};
('apply_type=sT,gray_type=reflected,radix=3' => $href,
'apply_type=sF,gray_type=reflected,radix=3' => $href,
);
# OEIS-Catalogue: A163344 planepath=GrayCode,apply_type=sT,radix=3 line_type=X_axis
# OEIS-Other: A163344 planepath=GrayCode,apply_type=sF,radix=3 line_type=X_axis
# OEIS-Other: A163343 planepath=GrayCode,apply_type=sT,radix=3 line_type=Diagonal
# OEIS-Other: A163343 planepath=GrayCode,apply_type=sF,radix=3 line_type=Diagonal
},
};
}
# { package Math::PlanePath::ImaginaryBase;
# }
{ package Math::PlanePath::ImaginaryHalf;
use constant _NumSeq_Y_axis_increasing => 1;
}
# { package Math::PlanePath::CubicBase;
# }
{ package Math::PlanePath::DekkingCurve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
}
{ package Math::PlanePath::DekkingCentres;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
}
{ package Math::PlanePath::CincoCurve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
}
{ package Math::PlanePath::BetaOmega;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
}
{ package Math::PlanePath::KochelCurve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
}
{ package Math::PlanePath::AR2W2Curve;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
}
{ package Math::PlanePath::WunderlichMeander;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
}
# { package Math::PlanePath::Flowsnake;
# }
# { package Math::PlanePath::FlowsnakeCentres;
# # inherit from Flowsnake
# }
# { package Math::PlanePath::GosperIslands;
# }
# { package Math::PlanePath::GosperSide;
# }
{ package Math::PlanePath::KochCurve;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_Diagonal_increasing => 1; # when touched
}
{ package Math::PlanePath::KochPeaks;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1; # when touched
# Diagonal never touched
}
{ package Math::PlanePath::KochSnowflakes;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::KochSquareflakes;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::QuadricCurve;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Diagonal_increasing => 1; # two values only
}
{ package Math::PlanePath::QuadricIslands;
# FIXME: pred() on Diagonal_SW doesn't notice 0.5 square
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 0;
use constant _NumSeq_Y_neg_increasing_from_i => 1; # after 3,2,8
use constant _NumSeq_Y_neg_min => 2; # at X=-1,Y=0 rather than X=0,Y=0
use constant _NumSeq_Diagonal_SW_increasing => 0;
use constant _NumSeq_Diagonal_SW_min => 1;
}
{ package Math::PlanePath::SierpinskiTriangle;
use constant _NumSeq_X_axis_increasing => 1; # for "diagonal" style
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
# low 10111=23 increment to 11000=24
# 10111 ones=4 width=2^4
# cf A160722 is 3*A006046-2*n, drawing three Sierpinski triangles
# http://www.polprimos.com/imagenespub/polca722.jpg
#
use constant _NumSeq_N_oeis_anum =>
{
#---------
# i_start=0, n_start=0
'align=triangular,n_start=0' =>
{ Diagonal_NW => 'A006046',
Depth_start => 'A006046',
# OEIS-Other: A006046 planepath=SierpinskiTriangle line_type=Diagonal_NW
# OEIS-Other: A006046 planepath=SierpinskiTriangle line_type=Depth_start
},
'align=right,n_start=0' =>
{ Y_axis => 'A006046',
Depth_start => 'A006046',
# OEIS-Catalogue: A006046 planepath=SierpinskiTriangle,align=diagonal,n_start=0 line_type=Y_axis
},
'align=left,n_start=0' =>
{ Diagonal_NW => 'A006046',
Depth_start => 'A006046',
# OEIS-Other: A006046 planepath=SierpinskiTriangle,align=left,n_start=0 line_type=Diagonal_NW
},
'align=diagonal,n_start=0' =>
{ Y_axis => 'A006046',
Depth_start => 'A006046',
# OEIS-Other: A006046 planepath=SierpinskiTriangle,align=diagonal,n_start=0 line_type=Y_axis
},
#---------
# i_start=1, n_start=0
# starting OFFSET=1 value=2,4,8,10 so missing N=0 at Y=0, hence i_start=1
'align=triangular,n_start=0,i_start=1' =>
{ Diagonal => 'A074330',
Depth_end => 'A074330',
# OEIS-Catalogue: A074330 planepath=SierpinskiTriangle line_type=Diagonal i_start=1
# OEIS-Other: A074330 planepath=SierpinskiTriangle line_type=Depth_end i_start=1
},
'align=right,n_start=0,i_start=1' =>
{ Diagonal => 'A074330',
Depth_end => 'A074330',
# OEIS-Other: A074330 planepath=SierpinskiTriangle,align=right line_type=Diagonal i_start=1
},
'align=left,n_start=0,i_start=1' =>
{ Y_axis => 'A074330',
Depth_end => 'A074330',
# OEIS-Other: A074330 planepath=SierpinskiTriangle,align=left line_type=Y_axis i_start=1
},
'align=diagonal,n_start=0,i_start=1' =>
{ X_axis => 'A074330',
Depth_end => 'A074330',
# OEIS-Other: A074330 planepath=SierpinskiTriangle,align=diagonal line_type=X_axis i_start=1
},
};
}
{ package Math::PlanePath::SierpinskiArrowhead;
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
# align="diagonal" is X increasing, other align is single origin point only
use constant _NumSeq_X_axis_increasing => 1;
}
{ package Math::PlanePath::SierpinskiArrowheadCentres;
use constant _NumSeq_Y_axis_increasing => 1; # never touched ?
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
# align="diagonal" is X increasing, other align is single origin point only
use constant _NumSeq_X_axis_increasing => 1;
}
{ package Math::PlanePath::SierpinskiCurve;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_X_axis_i_start => 1; # but not all cells visited
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_i_start => 1; # but not all cells visited
use constant _NumSeq_X_neg_increasing => 1; # arms
use constant _NumSeq_Y_neg_increasing => 1; # arms
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::SierpinskiCurveStair;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_X_neg_increasing => 1; # arms
use constant _NumSeq_Y_neg_increasing => 1; # arms
use constant _NumSeq_Diagonal_increasing => 1; # when touched
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
}
{ package Math::PlanePath::HIndexing;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when touched
}
# { package Math::PlanePath::DragonCurve;
# }
# { package Math::PlanePath::DragonRounded;
# }
# { package Math::PlanePath::DragonMidpoint;
# }
{ package Math::PlanePath::AlternatePaper;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1; # arms
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# selecting the smaller N on the negative axes gives increasing, maybe
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'arms=1' =>
{ X_axis => 'A000695', # base 4 digits 0,1 only
Diagonal => 'A062880', # base 4 digits 0,2 only
# OEIS-Other: A000695 planepath=AlternatePaper
# OEIS-Other: A062880 planepath=AlternatePaper line_type=Diagonal
},
};
}
{ package Math::PlanePath::AlternatePaperMidpoint;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1; # arms
use constant _NumSeq_Diagonal_SE_increasing => 1; # arms
}
# { package Math::PlanePath::TerdragonCurve;
# }
# { package Math::PlanePath::TerdragonRounded;
# }
# { package Math::PlanePath::TerdragonMidpoint;
# }
# { package Math::PlanePath::R5DragonCurve;
# }
# { package Math::PlanePath::R5DragonMidpoint;
# }
# { package Math::PlanePath::CCurve;
# }
# { package Math::PlanePath::ComplexPlus;
# }
{ package Math::PlanePath::ComplexMinus;
use constant _NumSeq_N_oeis_anum =>
{ 'realpart=1' =>
{ X_axis => 'A066321', # binary base i-1
# OEIS-Catalogue: A066321 planepath=ComplexMinus
# cf A066323 count of 1-bits in N on X axis
},
};
}
# { package Math::PlanePath::ComplexRevolving;
# }
{ package Math::PlanePath::Rows;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Y_neg_min => undef; # negatives
use constant _NumSeq_Y_neg_max => 1; # negatives
# secret negatives
# (w-1)*(w-1)-1
# = w^2-2w+1-1
# = w(w-2)
sub _NumSeq_Diagonal_SE_min {
my ($self) = @_;
return ($self->{'width'}-2)*$self->{'width'};
}
use constant _NumSeq_N_oeis_anum =>
{
'n_start=0,width=1' =>
{ X_axis => 'A001477', # integers 0,1,2,3,etc
# OEIS-Other: A001477 planepath=Rows,width=1,n_start=0 line_type=X_axis
},
'n_start=1,width=2' =>
{ Y_axis => 'A005408', # odd 2n+1
# OEIS-Other: A005408 planepath=Rows,width=2 line_type=Y_axis
},
'n_start=1,width=3' =>
{ Y_axis => 'A016777', # 3n+1
# OEIS-Catalogue: A016777 planepath=Rows,width=3 line_type=Y_axis
},
'n_start=1,width=4' =>
{ Y_axis => 'A016813', # 4n+1
# OEIS-Catalogue: A016813 planepath=Rows,width=4 line_type=Y_axis
},
'n_start=1,width=5' =>
{ Y_axis => 'A016861', # 5n+1
# OEIS-Catalogue: A016861 planepath=Rows,width=5 line_type=Y_axis
},
'n_start=1,width=6' =>
{ Y_axis => 'A016921', # 6n+1
# OEIS-Catalogue: A016921 planepath=Rows,width=6 line_type=Y_axis
},
'n_start=1,width=7' =>
{ Y_axis => 'A016993', # 7n+1
# OEIS-Catalogue: A016993 planepath=Rows,width=7 line_type=Y_axis
},
};
}
{ package Math::PlanePath::Columns;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_X_neg_min => undef; # negatives
use constant _NumSeq_X_neg_max => 1; # negatives
sub _NumSeq_Diagonal_NW_min {
my ($self) = @_;
# secret negatives
return ($self->{'height'}-2)*$self->{'height'};
}
use constant _NumSeq_N_oeis_anum =>
{
'n_start=0,height=1' =>
{ X_axis => 'A001477', # integers 0,1,2,3,etc
# OEIS-Other: A001477 planepath=Columns,height=1,n_start=0 line_type=X_axis
},
'n_start=1,height=2' =>
{ X_axis => 'A005408', # odd 2n+1
# OEIS-Other: A005408 planepath=Columns,height=2 line_type=X_axis
},
'n_start=1,height=3' =>
{ X_axis => 'A016777', # 3n+1
# OEIS-Other: A016777 planepath=Columns,height=3 line_type=X_axis
},
'n_start=1,height=4' =>
{ X_axis => 'A016813', # 4n+1
# OEIS-Other: A016813 planepath=Columns,height=4 line_type=X_axis
},
'n_start=1,height=5' =>
{ X_axis => 'A016861', # 5n+1
# OEIS-Other: A016861 planepath=Columns,height=5 line_type=X_axis
},
'n_start=1,height=6' =>
{ X_axis => 'A016921', # 6n+1
# OEIS-Other: A016921 planepath=Columns,height=6 line_type=X_axis
},
'n_start=1,height=7' =>
{ X_axis => 'A016993', # 7n+1
# OEIS-Other: A016993 planepath=Columns,height=7 line_type=X_axis
},
};
}
{ package Math::PlanePath::Diagonals;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'direction=down,n_start=1,x_start=0,y_start=0' =>
{
# Diagonals X_axis -- triangular 1,3,6,etc, but starting i=0 value=1
Y_axis => 'A000124', # triangular+1 = n*(n+1)/2+1
Diagonal => 'A001844', # centred squares 2n(n+1)+1
# OEIS-Catalogue: A000124 planepath=Diagonals line_type=Y_axis
# OEIS-Catalogue: A001844 planepath=Diagonals line_type=Diagonal
},
'direction=up,n_start=1,x_start=0,y_start=0' =>
{
X_axis => 'A000124', # triangular+1 = n*(n+1)/2+1
Diagonal => 'A001844', # centred squares 2n(n+1)+1
# OEIS-Other: A000124 planepath=Diagonals,direction=up line_type=X_axis
# OEIS-Other: A001844 planepath=Diagonals,direction=up line_type=Diagonal
},
'direction=down,n_start=0,x_start=0,y_start=0' =>
{
X_axis => 'A000096', # n*(n+3)/2
Y_axis => 'A000217', # triangular n*(n+1)/2
# OEIS-Other: A000096 planepath=Diagonals,n_start=0 line_type=X_axis
# OEIS-Other: A000217 planepath=Diagonals,n_start=0 line_type=Y_axis
},
'direction=up,n_start=0,x_start=0,y_start=0' =>
{
X_axis => 'A000217', # triangular n*(n+1)/2
Y_axis => 'A000096', # n*(n+3)/2
# OEIS-Other: A000217 planepath=Diagonals,direction=up,n_start=0 line_type=X_axis
# OEIS-Other: A000096 planepath=Diagonals,direction=up,n_start=0 line_type=Y_axis
},
};
}
{ package Math::PlanePath::DiagonalsAlternating;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ Diagonal => 'A001844', # centred squares 2n(n+1)+1
# OEIS-Other: A001844 planepath=DiagonalsAlternating line_type=Diagonal
# Not quite, extra initial 1 or 0
# X_axis => 'A128918',
# Y_axis => 'A131179',
},
'n_start=0' =>
{ Diagonal => 'A046092', # 2*triangular
# OEIS-Other: A046092 planepath=DiagonalsAlternating,n_start=0 line_type=Diagonal
},
};
}
{ package Math::PlanePath::DiagonalsOctant;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
# 'direction=down,n_start=1' =>
# {
# Not quite, starting i=0 for square=1 cf A000290 starts 0
# # Diagonal => 'A000290', # squares
#
# Not quite, A033638 extra initial 1
# # Y_axis => 'A033638', # quarter squares + 1, 1,1,2,3,5,7,10,13
# }
# 'direction=up,n_start=1' =>
# {
# # Not quite, A002061 extra initial 1
# # Diagonal => 'A002061', # 1,1,3,7,13,21,31,43
# }
'direction=down,n_start=0' =>
{ Diagonal => 'A005563', # n*(n+2) 0,3,8,15,24
# OEIS-Other: A005563 planepath=DiagonalsOctant,n_start=0 line_type=Diagonal
# # Not quite, extra initial 0
# # Y_axis => 'A002620', # quarter squares 0,0,1,2,4,6,9,12,
},
'direction=up,n_start=0' =>
{ Diagonal => 'A002378', # pronic 0,2,6,12,20
# OEIS-Other: A002378 planepath=DiagonalsOctant,direction=up,n_start=0 line_type=Diagonal
# # Not quite, starts n=1 value=0 whereas start Y=0 value=0 here
# # Y_axis => 'A024206', # 0,1,3,5,8,11,15
},
};
}
{ package Math::PlanePath::MPeaks;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 0;
use constant _NumSeq_X_neg_increasing_from_i => 1;
use constant _NumSeq_X_neg_min => 1; # at X=-1,Y=0 rather than X=0,Y=0
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing_from_i => 1;
use constant _NumSeq_Diagonal_NW_min => 2; # at X=-1,Y=1
# MPeaks -- X_axis A045944 matchstick n(3n+2) but initial N=3
# MPeaks -- Diagonal,Y_axis hexagonal first,second spoke, but starting
# from 3
}
{ package Math::PlanePath::Staircase;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
'n_start=1' =>
{ Diagonal => 'A084849',
# OEIS-Other: A084849 planepath=Staircase line_type=Diagonal
},
'n_start=0' =>
{ Diagonal => 'A014105', # second hexagonals
# OEIS-Other: A014105 planepath=Staircase,n_start=0 line_type=Diagonal
},
'n_start=2' =>
{ Diagonal => 'A096376',
# OEIS-Catalogue: A096376 planepath=Staircase,n_start=2 line_type=Diagonal
# Not quite, A128918 has extra initial 1,1
# X_axis => 'A128918',
},
};
}
{ package Math::PlanePath::StaircaseAlternating;
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
return ($self->{'end_type'} eq 'square'
? 1
: 0); # backs-up
}
*_NumSeq_Y_axis_increasing = \&_NumSeq_X_axis_increasing;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
'end_type=jump,n_start=1' =>
{ Diagonal => 'A084849',
# OEIS-Other: A084849 planepath=StaircaseAlternating line_type=Diagonal
},
'end_type=jump,n_start=0' =>
{ Diagonal => 'A014105', # second hexagonals
# OEIS-Other: A014105 planepath=StaircaseAlternating,n_start=0 line_type=Diagonal
},
'end_type=jump,n_start=2' =>
{ Diagonal => 'A096376',
# OEIS-Other: A096376 planepath=StaircaseAlternating,n_start=2 line_type=Diagonal
},
'end_type=square,n_start=1' =>
{ Diagonal => 'A058331',
# OEIS-Other: A058331 planepath=StaircaseAlternating,end_type=square line_type=Diagonal
},
'end_type=square,n_start=0' =>
{ Diagonal => 'A001105',
# OEIS-Other: A001105 planepath=StaircaseAlternating,end_type=square,n_start=0 line_type=Diagonal
},
};
}
{ package Math::PlanePath::Corner;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ Y_axis => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=Corner line_type=Y_axis
},
'wider=0,n_start=0' =>
{ X_axis => 'A005563', # (n+1)^2-1
Y_axis => 'A000290', # squares
Diagonal => 'A002378', # pronic
# OEIS-Other: A005563 planepath=Corner,n_start=0 line_type=X_axis
# OEIS-Other: A000290 planepath=Corner,n_start=0 line_type=Y_axis
# OEIS-Other: A002378 planepath=Corner,n_start=0 line_type=Diagonal
},
'wider=0,n_start=2' =>
{ Y_axis => 'A059100', # n^2+2
Diagonal => 'A014206', # pronic+2
# OEIS-Catalogue: A059100 planepath=Corner,n_start=2 line_type=Y_axis
# OEIS-Catalogue: A014206 planepath=Corner,n_start=2 line_type=Diagonal
},
'wider=1,n_start=0' =>
{ Y_axis => 'A002378', # pronic
Diagonal => 'A005563', # (n+1)^2-1
# OEIS-Other: A002378 planepath=Corner,wider=1,n_start=0 line_type=Y_axis
# OEIS-Other: A005563 planepath=Corner,wider=1,n_start=0 line_type=Diagonal
},
'wider=1,n_start=2' =>
{ Y_axis => 'A014206', # pronic+2
# OEIS-Other: A014206 planepath=Corner,wider=1,n_start=2 line_type=Y_axis
},
'wider=2,n_start=0' =>
{ Y_axis => 'A005563', # (n+1)^2-1
Diagonal => 'A028552', # n(n+3)
# OEIS-Other: A005563 planepath=Corner,wider=2,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A028552 planepath=Corner,wider=2,n_start=0 line_type=Diagonal
},
'wider=2,n_start=1' =>
{ Diagonal => 'A028387', # n(n+3)+1 = n + (n+1)^2
# OEIS-Catalogue: A028387 planepath=Corner,wider=2,n_start=1 line_type=Diagonal
},
'wider=3,n_start=0' =>
{ Y_axis => 'A028552', # n(n+3)
# OEIS-Other: A028552 planepath=Corner,wider=3,n_start=0 line_type=Y_axis
},
};
}
{ package Math::PlanePath::PyramidRows;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # when covered, or single
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
# PyramidRows step=1
do {
my $href =
{ Y_axis => 'A000124', # triangular+1 = n*(n+1)/2+1
};
('step=1,align=centre,n_start=1' => $href,
'step=1,align=right,n_start=1' => $href);
# OEIS-Other: A000124 planepath=PyramidRows,step=1 line_type=Y_axis
# OEIS-Other: A000124 planepath=PyramidRows,step=1,align=right line_type=Y_axis
},
'step=1,align=left,n_start=1' =>
{ Diagonal_NW => 'A000124', # triangular+1 = n*(n+1)/2+1
# OEIS-Other: A000124 planepath=PyramidRows,step=1,align=left line_type=Diagonal_NW
},
do {
my $href =
{ Y_axis => 'A000217', # triangular
};
('step=1,align=centre,n_start=0' => $href,
'step=1,align=right,n_start=0' => $href);
# OEIS-Other: A000217 planepath=PyramidRows,step=1,n_start=0 line_type=Y_axis
# OEIS-Other: A000217 planepath=PyramidRows,step=1,align=right,n_start=0 line_type=Y_axis
},
'step=2,align=centre,n_start=1' =>
{ Diagonal_NW => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=PyramidRows,step=2 line_type=Diagonal_NW
# Not quite, n_start=1 means squares starting from 1 whereas A000290
# starts from 0
# Diagonal => 'A000290',
},
'step=2,align=centre,n_start=0' =>
{ Y_axis => 'A002378', # pronic
Diagonal => 'A005563',
Diagonal_NW => 'A000290', # squares
# OEIS-Other: A002378 planepath=PyramidRows,step=2,n_start=0 line_type=Y_axis
# OEIS-Other: A005563 planepath=PyramidRows,step=2,n_start=0 line_type=Diagonal
# OEIS-Other: A000290 planepath=PyramidRows,step=2,n_start=0 line_type=Diagonal_NW
},
'step=2,align=right,n_start=0' =>
{ Y_axis => 'A000290', # squares
Diagonal => 'A002378', # pronic
# OEIS-Other: A000290 planepath=PyramidRows,step=2,align=right,n_start=0 line_type=Y_axis
# OEIS-Other: A002378 planepath=PyramidRows,step=2,align=right,n_start=0 line_type=Diagonal
},
'step=2,align=left,n_start=0' =>
{ Y_axis => 'A005563',
Diagonal_NW => 'A002378', # pronic
# OEIS-Other: A005563 planepath=PyramidRows,step=2,align=left,n_start=0 line_type=Y_axis
# OEIS-Other: A002378 planepath=PyramidRows,step=2,align=left,n_start=0 line_type=Diagonal_NW
},
'step=2,align=centre,n_start=2' =>
{ Diagonal_NW => 'A059100', # n^2+2
# OEIS-Other: A059100 planepath=PyramidRows,step=2,n_start=2 line_type=Diagonal_NW
},
'step=2,align=right,n_start=2' =>
{ Y_axis => 'A059100', # n^2+2
# OEIS-Other: A059100 planepath=PyramidRows,step=2,align=right,n_start=2 line_type=Y_axis
},
'step=3,align=centre,n_start=1' =>
{ Y_axis => 'A104249',
Diagonal_NW => 'A143689',
# OEIS-Catalogue: A104249 planepath=PyramidRows,step=3 line_type=Y_axis
# OEIS-Catalogue: A143689 planepath=PyramidRows,step=3 line_type=Diagonal_NW
# Not quite OFFSET=1 cf start i=0 here
# Diagonal => 'A005448',
# # OEIS-Catalogue: A005448 planepath=PyramidRows,step=3 line_type=Diagonal
},
'step=3,align=right,n_start=1' =>
{ Y_axis => 'A143689',
Diagonal => 'A104249',
# OEIS-Other: A143689 planepath=PyramidRows,step=3,align=right line_type=Y_axis
# OEIS-Other: A104249 planepath=PyramidRows,step=3,align=right line_type=Diagonal
# Not quite OFFSET=1 cf start i=0 here
# Diagonal => 'A005448',
# # OEIS-Catalogue: A005448 planepath=PyramidRows,step=3 line_type=Diagonal
},
'step=3,align=centre,n_start=0' =>
{ Y_axis => 'A005449', # second pentagonal n*(3n+1)/2
Diagonal_NW => 'A000326', # pentagonal n(3n-1)/2
# OEIS-Other: A005449 planepath=PyramidRows,step=3,n_start=0 line_type=Y_axis
# OEIS-Other: A000326 planepath=PyramidRows,step=3,n_start=0 line_type=Diagonal_NW
},
'step=3,align=right,n_start=0' =>
{ Y_axis => 'A000326', # pentagonal n(3n-1)/2
Diagonal => 'A005449', # second pentagonal n*(3n+1)/2
# OEIS-Other: A000326 planepath=PyramidRows,step=3,align=right,n_start=0 line_type=Y_axis
# OEIS-Other: A005449 planepath=PyramidRows,step=3,align=right,n_start=0 line_type=Diagonal
},
'step=4,align=centre,n_start=1' =>
{ Y_axis => 'A084849',
Diagonal => 'A001844',
Diagonal_NW => 'A058331',
# OEIS-Catalogue: A084849 planepath=PyramidRows,step=4 line_type=Y_axis
# OEIS-Other: A001844 planepath=PyramidRows,step=4 line_type=Diagonal
# OEIS-Other: A058331 planepath=PyramidRows,step=4 line_type=Diagonal_NW
},
'step=4,align=right,n_start=1' =>
{ Diagonal => 'A058331',
# OEIS-Other: A058331 planepath=PyramidRows,step=4,align=right line_type=Diagonal
},
'step=4,align=left,n_start=1' =>
{ Diagonal_NW => 'A001844',
# OEIS-Other: A001844 planepath=PyramidRows,step=4,align=left line_type=Diagonal_NW
},
'step=4,align=centre,n_start=0' =>
{ Y_axis => 'A014105', # second hexagonal
Diagonal => 'A046092', # 4*triangular
Diagonal_NW => 'A001105', # 2*n^2
# OEIS-Other: A014105 planepath=PyramidRows,step=4,n_start=0 line_type=Y_axis
# OEIS-Catalogue: A046092 planepath=PyramidRows,step=4,n_start=0 line_type=Diagonal
# OEIS-Other: A001105 planepath=PyramidRows,step=4,n_start=0 line_type=Diagonal_NW
},
'step=4,align=right,n_start=0' =>
{ Y_axis => 'A000384', # 2*n^2-n, hexagonal numbers
Diagonal => 'A001105',
# OEIS-Other: A000384 planepath=PyramidRows,step=4,align=right,n_start=0 line_type=Y_axis
# OEIS-Other: A001105 planepath=PyramidRows,step=4,align=right,n_start=0 line_type=Diagonal
},
'step=4,align=left,n_start=0' =>
{ Diagonal_NW => 'A046092', # 4*triangular
# OEIS-Other: A046092 planepath=PyramidRows,step=4,align=left,n_start=0 line_type=Diagonal_NW
},
# TODO PyramidRows,step=5 n_start=0
'step=5,align=centre,n_start=1' =>
{ Y_axis => 'A116668',
# OEIS-Other: A116668 planepath=PyramidRows,step=5 line_type=Y_axis
},
'step=6,align=centre,n_start=1' =>
{ Diagonal_NW => 'A056107',
Y_axis => 'A056108',
Diagonal => 'A056109',
# OEIS-Other: A056107 planepath=PyramidRows,step=6 line_type=Diagonal_NW
# OEIS-Other: A056108 planepath=PyramidRows,step=6 line_type=Y_axis
# OEIS-Other: A056109 planepath=PyramidRows,step=6 line_type=Diagonal
},
'step=8,align=centre,n_start=1' =>
{ Diagonal_NW => 'A053755',
# OEIS-Other: A053755 planepath=PyramidRows,step=8 line_type=Diagonal_NW
},
'step=9,align=centre,n_start=1' =>
{ Y_axis => 'A006137',
Diagonal => 'A038764',
# OEIS-Other: A006137 planepath=PyramidRows,step=9 line_type=Y_axis
# OEIS-Other: A038764 planepath=PyramidRows,step=9 line_type=Diagonal
},
};
}
{ package Math::PlanePath::PyramidSides;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ X_neg => 'A002522',
Diagonal => 'A033951',
# OEIS-Catalogue: A002522 planepath=PyramidSides line_type=X_neg
# OEIS-Other: A033951 planepath=PyramidSides line_type=Diagonal
#
# X_axis -- squares (x+1)^2, but starting i=0 value=1
} };
}
{ package Math::PlanePath::CellularRule;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'rule=5,n_start=1' =>
{ Y_axis => 'A061925', # ceil(n^2/2)+1
# OEIS-Catalogue: A061925 planepath=CellularRule,rule=5 line_type=Y_axis
},
# rule 84,116,212,244 two-wide right line
do {
my $tworight
= { Diagonal => 'A005408', # odds 2n+1
};
('rule=84,n_start=1' => $tworight,
'rule=116,n_start=1' => $tworight,
'rule=212,n_start=1' => $tworight,
'rule=244,n_start=1' => $tworight,
);
# OEIS-Other: A005408 planepath=CellularRule,rule=84 line_type=Diagonal
# OEIS-Other: A005408 planepath=CellularRule,rule=116 line_type=Diagonal
# OEIS-Other: A005408 planepath=CellularRule,rule=212 line_type=Diagonal
# OEIS-Other: A005408 planepath=CellularRule,rule=244 line_type=Diagonal
},
'rule=77,n_start=1' =>
{ Y_axis => 'A000124', # triangular+1
# OEIS-Other: A000124 planepath=CellularRule,rule=77 line_type=Y_axis
},
'rule=177,n_start=1' =>
{ Diagonal => 'A000124', # triangular+1
# OEIS-Other: A000124 planepath=CellularRule,rule=177 line_type=Diagonal
},
'rule=185,n_start=1' =>
{ Diagonal => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=CellularRule,rule=185 line_type=Diagonal
},
'rule=189,n_start=1' =>
{ Y_axis => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=CellularRule,rule=189 line_type=Y_axis
},
# PyramidRows step=1,align=left
# OEIS-Other: A000124 planepath=CellularRule,rule=206 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=238 line_type=Diagonal_NW
do {
my $solidgapright
= { Diagonal => 'A002522', # n^2+1
};
('rule=209,n_start=1' => $solidgapright,
'rule=241,n_start=1' => $solidgapright,
);
# OEIS-Other: A002522 planepath=CellularRule,rule=209 line_type=Diagonal
# OEIS-Other: A002522 planepath=CellularRule,rule=241 line_type=Diagonal
},
'rule=29,n_start=1' =>
{ Y_axis => 'A000124', # triangular+1
# OEIS-Other: A000124 planepath=CellularRule,rule=29 line_type=Y_axis
},
'rule=221,n_start=1' =>
{ Y_axis => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=CellularRule,rule=221 line_type=Y_axis
},
'rule=229,n_start=1' =>
{ Y_axis => 'A002522', # n^2+1
# OEIS-Other: A002522 planepath=CellularRule,rule=229 line_type=Y_axis
},
#
# rule=13 Y axis
#
# rule=28,156
# Y_axis => 'A002620', quarter squares floor(n^2/4) but diff start
# Diagonal => 'A024206', quarter squares - 1, but diff start
#
# A000027 naturals integers 1 upwards, but OFFSET=1 cf start Y=0 here
# # central column only
# 'rule=4' =>
# { Y_axis => 'A000027', # 1 upwards
# # OEIS-Other: A000027 planepath=CellularRule,rule=4 line_type=Y_axis
# },
#
# # right line only rule=16,24,48,56,80,88,112,120,144,152,176,184,208,216,240,248
# Not quite A000027 OFFSET=1 vs start X=Y=0 here
# 'rule=16' =>
# { Y_axis => 'A000027', # 1 upwards
# # OEIS-Other: A000027 planepath=CellularRule,rule=16 line_type=Diagonal
# },
};
}
{
package Math::PlanePath::CellularRule::Line;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
}
{
package Math::PlanePath::CellularRule::OneTwo;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
# use constant _NumSeq_N_oeis_anum =>
# { 'align=left,n_start=1' =>
# {
# Not quite, OFFSET=1 cf coordinate X=0 here
# Diagonal_NW => 'A001651', # not divisible by 3
# },
# { 'align=right,n_start=1' =>
# Not quite, A032766 0 or 1 mod 3, but it starts OFFSET=0 value=0
# whereas path start 1,3,4,etc without initial 0
# Diagonal => 'A032766',
#
# };
}
{
package Math::PlanePath::CellularRule::OddSolid;
# rule=50,58,114,122,178,179,186,242,250 pyramid every second point
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ Diagonal_NW => 'A000124', # triangular+1
# OEIS-Other: A000124 planepath=CellularRule,rule=50 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=58 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=114 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=122 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=178 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=179 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=186 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=242 line_type=Diagonal_NW
# OEIS-Other: A000124 planepath=CellularRule,rule=250 line_type=Diagonal_NW
#
# Not quite, starts value=0
# Diagonal => 'A000217', # triangular numbers but diff start
},
};
}
{ package Math::PlanePath::CellularRule54;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
}
{ package Math::PlanePath::CellularRule57;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
}
{ package Math::PlanePath::CellularRule190;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'mirror=0,n_start=0' =>
{ Diagonal_NW => 'A006578', # triangular and quarter square
# OEIS-Catalogue: A006578 planepath=CellularRule190,n_start=0 line_type=Diagonal_NW
},
'mirror=1,n_start=0' =>
{ Diagonal_NW => 'A006578', # triangular and quarter square
# OEIS-Other: A006578 planepath=CellularRule190,mirror=1,n_start=0 line_type=Diagonal_NW
},
};
}
{ package Math::PlanePath::UlamWarburton;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'parts=4,n_start=0' =>
{ Depth_start => 'A147562', # cells ON after n stages
# OEIS-Catalogue: A147562 planepath=UlamWarburton,n_start=0 line_type=Depth_start
},
'parts=2,n_start=0' =>
{ Depth_start => 'A183060', # num cells ON, starting from 0
X_axis => 'A183060', # X_axis == Depth_start
# OEIS-Catalogue: A183060 planepath=UlamWarburton,parts=2,n_start=0 line_type=Depth_start
# OEIS-Other: A183060 planepath=UlamWarburton,parts=2,n_start=0 line_type=X_axis
},
'parts=1,n_start=1' =>
{ Depth_end => 'A151922', # num cells ON at end of depth=n
Y_axis => 'A151922', # Y_axis == Depth_end
# OEIS-Catalogue: A151922 planepath=UlamWarburton,parts=1,n_start=1 line_type=Depth_end
# OEIS-Other: A151922 planepath=UlamWarburton,parts=1,n_start=1 line_type=Y_axis
},
};
}
{ package Math::PlanePath::UlamWarburtonQuarter;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
# low 10111=23 increment to 11000=24
# 4^2*3+4*3^2+1*3^3 = 111 123
# 4^3*3 = 192 150 +27 = 3^3
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ Depth_end => 'A151920', # 3^count1bits(n), OFFSET=0 1,2,5,6,9
# OEIS-Catalogue: A151920 planepath=UlamWarburtonQuarter line_type=Depth_end
},
};
}
{ package Math::PlanePath::CoprimeColumns;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_X_offset => 1;
# CoprimeColumns
# X_axis => 'A002088', # cumulative totient but start X=1 value=0;
# Diagonal A015614 cumulative-1 but start X=1 value=1
}
{ package Math::PlanePath::DivisibleColumns;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
# Not quite, X_axis => 'A006218' but path start X=1 cf OFFSET=0,
# Not quite, Diagonal => 'A077597' but path start X=1 cf OFFSET=0
}
# { package Math::PlanePath::File;
# # File points from a disk file
# # FIXME: analyze points for min/max
# }
# { package Math::PlanePath::QuintetCurve;
# }
# { package Math::PlanePath::QuintetCentres;
# # inherit QuintetCurve
# }
{ package Math::PlanePath::CornerReplicate;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ '' =>
{ X_axis => 'A000695', # base 4 digits 0,1 only
Y_axis => 'A001196', # base 4 digits 0,3 only
Diagonal => 'A062880', # base 4 digits 0,2 only
# OEIS-Other: A000695 planepath=CornerReplicate
# OEIS-Other: A001196 planepath=CornerReplicate line_type=Y_axis
# OEIS-Other: A062880 planepath=CornerReplicate line_type=Diagonal
},
};
}
{ package Math::PlanePath::DigitGroups;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'radix=2,i_start=1' =>
{ X_axis => 'A084471', # 0 -> 00 in binary, starting OFFSET=1
# OEIS-Catalogue: A084471 planepath=DigitGroups,radix=2 i_start=1
},
};
}
{ package Math::PlanePath::FibonacciWordFractal;
use constant _NumSeq_X_axis_increasing => 1; # when touched
use constant _NumSeq_Y_axis_increasing => 1; # when touched
use constant _NumSeq_Diagonal_increasing => 1; # when touched
}
{ package Math::PlanePath::LTiling;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{ 'L_fill=middle' =>
{ Diagonal => 'A062880', # base 4 digits 0,2 only
# OEIS-Other: A062880 planepath=LTiling line_type=Diagonal
},
};
}
{ package Math::PlanePath::WythoffArray;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_N_oeis_anum =>
{
'x_start=1,y_start=1' =>
{ Y_axis => 'A003622', # spectrum of phi 1,4,6,9
Diagonal => 'A020941', # diagonal, OFFSET=1
# OEIS-Catalogue: A003622 planepath=WythoffArray,x_start=1,y_start=1 line_type=Y_axis
# OEIS-Catalogue: A020941 planepath=WythoffArray,x_start=1,y_start=1 line_type=Diagonal
# Y=1 every second => 'A005248', # every second Lucas number
},
# # Not quite, extra initial 0,1 in A000045 Fibonaccis
# # X_axis => 'A000045',
#
# # Y=1 row X=0,2,4,etc => 'A005248', # every second Lucas number
};
}
{ package Math::PlanePath::PowerArray;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
# cf Not quite A168183 non-multiples-of-9, A168186 non-multiples-of-12
# are values on Y axis, except OFFSET=1 value=1, whereas path start Y=0
# value=1
use constant _NumSeq_N_oeis_anum =>
{ 'radix=2' =>
{ X_axis => 'A000079', # powers 2^X
Y_axis => 'A005408', # odd 2n+1
Diagonal => 'A014480', # (2n+1)*2^n starting n=0
# OEIS-Other: A000079 planepath=PowerArray
# OEIS-Other: A005408 planepath=PowerArray line_type=Y_axis
# OEIS-Catalogue: A014480 planepath=PowerArray line_type=Diagonal
},
'radix=3' =>
{ X_axis => 'A000244', # powers 3^X
# OEIS-Other: A000244 planepath=PowerArray,radix=3
#
# Not quite, OFFSET=1 cf path start Y=0
# Y_axis => 'A001651', # non multiples of 3
},
'radix=4' =>
{ X_axis => 'A000302', # powers 4^X
# OEIS-Other: A000302 planepath=PowerArray,radix=4
},
'radix=5' =>
{ X_axis => 'A000351', # powers 5^X
# OEIS-Other: A000351 planepath=PowerArray,radix=5
},
'radix=10' =>
{ X_axis => 'A011557', # powers 10^X
# OEIS-Other: A011557 planepath=PowerArray,radix=10
# Not quite, A067251 OFFSET=1 value=1 whereas path Y=0 N=value=1
# Y_axis => 'A067251', # no trailing 0 digits
# # OEIS-Catalogue: A067251 planepath=PowerArray,radix=10 line_type=Y_axis
},
};
}
#------------------------------------------------------------------------------
# Math-PlanePath-Toothpick
{ package Math::PlanePath::ToothpickTree;
# X axis has N=0 or N=0,1 only, except for parts=octant axis at Y=1
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
return ($self->{'parts'} ne 'octant');
}
# Y axis has N=0,N=1 only, except for parts=octant_up axis at X=1
sub _NumSeq_Y_axis_increasing {
my ($self) = @_;
return ($self->{'parts'} ne 'octant_up');
}
use constant _NumSeq_Y_neg_increasing => 1; # N=0,N=2 only
use constant _NumSeq_Diagonal_increasing => 1; # growth steps along diags
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ 'parts=4' =>
{ Depth_start => 'A139250',
# OEIS-Other: A139250 planepath=ToothpickTree,parts=4 line_type=Depth_start
},
'parts=3' =>
{ Depth_start => 'A153006',
# OEIS-Other: A153006 planepath=ToothpickTree,parts=3 line_type=Depth_start
},
'parts=2' =>
{ Depth_start => 'A152998',
# OEIS-Other: A152998 planepath=ToothpickTree,parts=2 line_type=Depth_start
},
'parts=1' =>
{ Depth_start => 'A153000',
# OEIS-Other: A153000 planepath=ToothpickTree,parts=1 line_type=Depth_start
},
'parts=wedge' =>
{ Depth_start => 'A160406',
# OEIS-Other: A160406 planepath=ToothpickTree,parts=wedge line_type=Depth_start
},
'parts=two_horiz' =>
{ Depth_start => 'A160158',
# OEIS-Other: A160158 planepath=ToothpickTree,parts=two_horiz line_type=Depth_start
},
};
}
{ package Math::PlanePath::ToothpickReplicate;
use constant _NumSeq_Y_axis_increasing => 1; # N=0,N=1 only
sub _NumSeq_Y_neg_increasing {
my ($self) = @_;
return ($self->{'parts'} == 3 ? 0 # replication twist
: 1); # N=0,N=2 only
}
use constant _NumSeq_Diagonal_increasing => 1; # replicate along diags
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
}
{ package Math::PlanePath::ToothpickUpist;
use constant _NumSeq_Y_axis_increasing => 1; # rows increasing
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ '' =>
{ Depth_start => 'A151566',
# OEIS-Other: A151566 planepath=ToothpickUpist line_type=Depth_start
},
};
}
{ package Math::PlanePath::ToothpickSpiral;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ 'n_start=1' =>
{ Diagonal => 'A014634', # odd-index hexagonals
Diagonal_NW => 'A033567', #
Diagonal_SW => 'A185438', #
Diagonal_SE => 'A188135', #
# OEIS-Other: A014634 planepath=ToothpickSpiral line_type=Diagonal
# OEIS-Other: A033567 planepath=ToothpickSpiral line_type=Diagonal_NW
# OEIS-Other: A185438 planepath=ToothpickSpiral line_type=Diagonal_SW
# OEIS-Other: A188135 planepath=ToothpickSpiral line_type=Diagonal_SE
},
'n_start=0' =>
{ Diagonal => 'A033587', #
Diagonal_SW => 'A014635', # even-index hexagonals
Diagonal_SE => 'A033585', #
# OEIS-Other: A033587 planepath=ToothpickSpiral,n_start=0 line_type=Diagonal
# OEIS-Other: A014635 planepath=ToothpickSpiral,n_start=0 line_type=Diagonal_SW
# OEIS-Other: A033585 planepath=ToothpickSpiral,n_start=0 line_type=Diagonal_SE
},
};
}
{ package Math::PlanePath::LCornerTree;
sub _NumSeq_X_axis_increasing {
my ($self) = @_;
return $self->{'parts'} ne 'diagonal-1';
}
{
my %_NumSeq_Y_axis_increasing = ('octant+1' => 1, # two points only
'diagonal-1' => 1,
);
sub _NumSeq_Y_axis_increasing {
my ($self) = @_;
return $_NumSeq_Y_axis_increasing{$self->{'parts'}};
}
}
sub _NumSeq_X_neg_increasing {
my ($self) = @_;
return ($self->{'parts'} eq 'wedge' # two points N=0,N=1
|| $self->{'parts'} eq 'wedge+1' # three points N=0,1,7
|| $self->{'parts'} eq 'diagonal');
}
# parts=diagonal has minimum N=0 at X=0,Y=-1, so explicit Y_neg minimum
use constant _NumSeq_Y_neg_min => 0;
sub _NumSeq_Y_neg_increasing {
my ($self) = @_;
return $self->{'parts'} ne 'diagonal';
}
use constant _NumSeq_Diagonal_increasing => 1; # growth along diags
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ 'parts=4' =>
{ Depth_start => 'A160410', # 4 * cumulative 3^count1bits(n)
# OEIS-Other: A160410 planepath=LCornerTree line_type=Depth_start
},
'parts=3' =>
{ Depth_start => 'A160412', # 3 * cumulative 3^count1bits(n)
# OEIS-Other: A160412 planepath=LCornerTree,parts=3 line_type=Depth_start
},
'parts=diagonal-1' =>
{ Depth_start => 'A183148', # half-plane triplet toothpicks
# OEIS-Other: A183148 planepath=LCornerTree,parts=diagonal-1 line_type=Depth_start
},
# Not quite, A130665=1,4,7,16 offset=0 whereas Nend=0,1,4,7,16 depth=0
# has extra initial 0.
# 'parts=1' =>
# { Depth_end => 'A130665', # cumulative 3^count1bits(d), starting a(0)=1
# # OEIS-Catalogue: A130665 planepath=LCornerTree,parts=1,n_start=-1 line_type=Depth_end i_offset=1
# },
};
}
{ package Math::PlanePath::LCornerReplicate;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1; # replicate along diags
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ '' =>
{ Diagonal => 'A062880', # base 4 digits 0,2 only
# OEIS-Other: A062880 planepath=LCornerReplicate line_type=Diagonal
},
};
}
{ package Math::PlanePath::OneOfEight;
use constant _NumSeq_X_axis_increasing => 1;
use constant _NumSeq_X_neg_increasing => 1;
use constant _NumSeq_Y_axis_increasing => 1;
use constant _NumSeq_Y_neg_increasing => 1;
use constant _NumSeq_Diagonal_increasing => 1;
use constant _NumSeq_Diagonal_NW_increasing => 1;
use constant _NumSeq_Diagonal_SW_increasing => 1;
use constant _NumSeq_Diagonal_SE_increasing => 1;
# catalogued in Math::NumSeq::OEIS::Catalogue::Plugin::PlanePathToothpick
use constant _NumSeq_N_oeis_anum =>
{ 'parts=4' =>
{ Depth_start => 'A151725',
# OEIS-Other: A151725 planepath=OneOfEight line_type=Depth_start
},
'parts=1' =>
{ Depth_start => 'A151735',
# OEIS-Other: A151735 planepath=OneOfEight,parts=1 line_type=Depth_start
},
'parts=3mid' =>
{ Depth_start => 'A170880',
# OEIS-Other: A170880 planepath=OneOfEight,parts=3mid line_type=Depth_start
},
'parts=3side' =>
{ Depth_start => 'A170879',
# OEIS-Other: A170879 planepath=OneOfEight,parts=3side line_type=Depth_start
},
};
}
{ package Math::PlanePath::HTree;
# clockwise around each sub-tree so N increases along X axis
use constant _NumSeq_X_axis_increasing => 1;
}
#------------------------------------------------------------------------------
{ package Math::PlanePath;
use constant _NumSeq_A2 => 0;
}
{ package Math::PlanePath::TriangleSpiral;
use constant _NumSeq_A2 => 1;
}
{ package Math::PlanePath::HexSpiral;
use constant _NumSeq_A2 => 1;
}
{ package Math::PlanePath::HexArms;
use constant _NumSeq_A2 => 1;
}
{ package Math::PlanePath::TriangularHypot;
use constant _NumSeq_A2 => 1;
}
{ package Math::PlanePath::Flowsnake;
use constant _NumSeq_A2 => 1;
# and FlowsnakeCentres inherits
}
1;
__END__
=for stopwords Ryde Math-PlanePath SquareSpiral lookup PlanePath ie
=head1 NAME
Math::NumSeq::PlanePathN -- sequence of N values from PlanePath module
=head1 SYNOPSIS
use Math::NumSeq::PlanePathN;
my $seq = Math::NumSeq::PlanePathN->new (planepath => 'SquareSpiral',
line_type => 'X_axis');
my ($i, $value) = $seq->next;
=head1 DESCRIPTION
This module presents N values from a C as a sequence. The
default is the X axis, or the C parameter (a string) can choose
among
"X_axis" X axis
"Y_axis" Y axis
"X_neg" X negative axis
"Y_neg" Y negative axis
"Diagonal" leading diagonal X=i, Y=i
"Diagonal_NW" north-west diagonal X=-i, Y=i
"Diagonal_SW" south-west diagonal X=-i, Y=-i
"Diagonal_SE" south-east diagonal X=i, Y=-i
"Depth_start" first N at depth=i
"Depth_end" last N at depth=i
For example the C X axis starts i=0 with values 1, 2, 11, 28,
53, 86, etc.
"X_neg", "Y_neg", "Diagonal_NW", etc, on paths which don't traverse negative
X or Y have just a single value from X=0,Y=0.
The behaviour on paths which visit only some of the points on the respective
axis is unspecified as yet, as is behaviour on paths with repeat points,
such as the C.
=head1 FUNCTIONS
See L for behaviour common to all sequence classes.
=over 4
=item C<$seq = Math::NumSeq::PlanePathN-Enew (key=Evalue,...)>
Create and return a new sequence object. The options are
planepath string, name of a PlanePath module
planepath_object PlanePath object
line_type string, as described above
C can be either the module part such as "SquareSpiral" or a
full class name "Math::PlanePath::SquareSpiral".
=item C<$value = $seq-Eith($i)>
Return the N value at C<$i> in the PlanePath. C<$i> gives a position on the
respective C, so the X,Y to lookup a C<$value=N> is
X,Y line_type
----- ---------
$i, 0 "X_axis"
0, $i "Y_axis"
-$i, 0 "X_neg"
0, -$i "Y_neg"
$i, $i "Diagonal"
$i, -$i "Diagonal_NW"
-$i, -$i "Diagonal_SW"
$i, -$i "Diagonal_SE"
=item C<$bool = $seq-Epred($value)>
Return true if C<$value> occurs in the sequence.
This means C<$value> is an integer N which is on the respective
C, ie. that C<($path-En_to_xy($value)> is on the line type.
=back
=head1 SEE ALSO
L,
L,
L
=head1 HOME PAGE
L
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/lib/Math/NumSeq/PlanePathCoord.pm 0000644 0001750 0001750 00000543621 12255452156 017771 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Maybe:
#
# LeafDist
# LeafDistDown
#
# Numerator = X*sgn(Y) / gcd(X,Y) X/Y in least terms, num + or -
# Denominator = abs(Y) / gcd(X,Y) den >=0
# X/0 keep as numerator=X ? or reduce to 1/0 ?
# 0/Y keep as denominator=Y ? or reduce to 0/1 ?
#
# ParentDegree -- num siblings and also self
#
# CfracLength,GcdDivisions,GcdSteps,EuclidSteps
# -- terms in cfrac(X/Y), excluding int=0 if X=1
#
# KroneckerSymbol(a,b) (a/2)=(2/a), or (a/2)=0 if a even
#
# Theta angle in radians
# AngleFrac
# AngleRadians
# Theta360 angle matching Radius,RSquared
# TTheta360 angle matching TRadius,TRSquared
#
# IsRational -- Chi(x) = 1 if x rational, 0 if irrational
# Dirichlet function D(x) = 1/b if rational x=a/b least terms, 0 if irrational
# Multiplicative distance A130836 X,Y>=1
# sum abs(exponent-exponent) of each prime
# A130849 total/2 muldist along diagonal
package Math::NumSeq::PlanePathCoord;
use 5.004;
use strict;
use Carp;
use constant 1.02; # various underscore constants below
use List::Util;
#use List::Util 'max','min';
*max = \&Math::PlanePath::_max;
*min = \&Math::PlanePath::_min;
use vars '$VERSION','@ISA';
$VERSION = 113;
use Math::NumSeq;
@ISA = ('Math::NumSeq');
use Math::PlanePath;
*_divrem = \&Math::PlanePath::_divrem;
use Math::PlanePath::Base::Generic
'is_infinite';
# uncomment this to run the ### lines
# use Smart::Comments;
sub description {
my ($self) = @_;
if (ref $self) {
return "Coordinate $self->{'coordinate_type'} values from path $self->{'planepath'}";
} else {
# class method
return 'Coordinate values from a PlanePath';
}
}
use constant::defer parameter_info_array =>
sub {
my $choices = [
'X', 'Y',
'Sum', 'SumAbs',
'Product',
'DiffXY', 'DiffYX', 'AbsDiff',
'Radius', 'RSquared',
'TRadius', 'TRSquared',
'IntXY', 'FracXY',
'BitAnd', 'BitOr', 'BitXor',
'Min','Max',
'MinAbs','MaxAbs',
'GCD',
'Depth', 'SubHeight',
'NumChildren','NumSiblings',
'RootN',
'IsLeaf','IsNonLeaf',
# Maybe:
'MinAbsTri','MaxAbsTri',
# 'AbsX',
# 'AbsY',
# 'DiffXY/2',
# 'DiffXYsquares',
# 'DiffYXsquares',
# 'Parity',
# 'Numerator','Denominator',
# 'LeafDistance',
# 'GcdDivisions',
# 'KroneckerSymbol',
# 'MulDist',
# 'HammingDist',
# 'NumSurround4',
# 'NumSurround4d',
# 'NumSurround6',
# 'NumSurround8',
];
return [
_parameter_info_planepath(),
{ name => 'coordinate_type',
display => 'Coordinate Type',
type => 'enum',
default => 'X',
choices => $choices,
choices_display => $choices,
description => 'The coordinate or combination to take from the path.',
},
];
};
use constant::defer _parameter_info_planepath => sub {
# require Module::Util;
# cf ...::Generator->path_choices() order
# my @choices = sort map { s/.*:://;
# if (length() > $width) { $width = length() }
# $_ }
# Module::Util::find_in_namespace('Math::PlanePath');
# my @choices = Module::Find::findsubmod('Math::PlanePath');
# @choices = grep {$_ ne 'Math::PlanePath'} @choices;
# my $choices = ...::Generator->path_choices_array;
# foreach (@$choices) {
# if (length() > $width) { $width = length() }
# }
require File::Spec;
require Scalar::Util;
my $width = 0;
my %names;
foreach my $dir (@INC) {
next if ! defined $dir || ref $dir;
# next if ref $dir eq 'CODE' # subr
# || ref $dir eq 'ARRAY' # array of subr and more
# || Scalar::Util::blessed($dir);
opendir DIR, File::Spec->catdir ($dir, 'Math', 'PlanePath') or next;
while (my $name = readdir DIR) {
# basename of .pm files, and not emacs .#Foo.pm lockfiles
$name =~ s/^([^.].*)\.pm$/$1/
or next;
if (length($name) > $width) { $width = length($name) }
$names{$name} = 1;
}
closedir DIR;
}
my $choices = [ sort keys %names ];
return { name => 'planepath',
display => 'PlanePath Class',
type => 'string',
default => $choices->[0],
choices => $choices,
width => $width + 5,
description => 'PlanePath module name.',
};
};
#------------------------------------------------------------------------------
sub oeis_anum {
my ($self) = @_;
### PlanePathCoord oeis_anum() ...
my $planepath_object = $self->{'planepath_object'};
my $coordinate_type = $self->{'coordinate_type'};
if ($coordinate_type eq 'AbsX') {
if (! $planepath_object->x_negative) { $coordinate_type = 'X'; }
} elsif ($coordinate_type eq 'AbsY') {
if (! $planepath_object->y_negative) { $coordinate_type = 'Y'; }
}
if ($planepath_object->isa('Math::PlanePath::Rows')) {
if ($coordinate_type eq 'X') {
return _oeis_anum_modulo($planepath_object->{'width'});
}
} elsif ($planepath_object->isa('Math::PlanePath::Columns')) {
if ($coordinate_type eq 'Y') {
return _oeis_anum_modulo($planepath_object->{'height'});
}
}
{
my $key = Math::NumSeq::PlanePathCoord::_planepath_oeis_anum_key($self->{'planepath_object'});
my $i_start = $self->i_start;
if ($i_start != $self->default_i_start) {
### $i_start
### cf n_start: $planepath_object->n_start
$key .= ",i_start=$i_start";
}
### planepath: ref $planepath_object
### $key
### whole table: $planepath_object->_NumSeq_Coord_oeis_anum
### key href: $planepath_object->_NumSeq_Coord_oeis_anum->{$key}
if (my $anum = $planepath_object->_NumSeq_Coord_oeis_anum->{$key}->{$coordinate_type}) {
return $anum;
}
}
# all-zeros
if (defined (my $values_min = $self->values_min)) {
if (defined (my $values_max = $self->values_max)) {
if ($values_min == 0 && $values_max == 0) {
return 'A000004'; # all 0s
}
if ($values_min == 2 && $values_max == 2) {
return 'A007395'; # all 2s
}
}
}
return undef;
}
sub _oeis_anum_modulo {
my ($modulus) = @_;
require Math::NumSeq::Modulo;
return Math::NumSeq::Modulo->new(modulus=>$modulus)->oeis_anum;
}
sub _planepath_oeis_key {
my ($path) = @_;
### PlanePathCoord _planepath_oeis_key() ...
return join(',',
ref($path),
(map {
# nasty hack to exclude SierpinskiCurveStair diagonal_length
$_->{'name'} eq 'diagonal_length'
? ()
: do {
my $value = $path->{$_->{'name'}};
if ($_->{'type'} eq 'boolean') {
$value = ($value ? 1 : 0);
}
### $_
### $value
### gives: "$_->{'name'}=$value"
(defined $value ? "$_->{'name'}=$value" : ())
}
}
_planepath_oeis_anum_parameter_info_list($path)));
}
sub _planepath_oeis_anum_key {
my ($path) = @_;
### PlanePathCoord _planepath_oeis_key() ...
return join(',',
(map {
# nasty hack to exclude SierpinskiCurveStair diagonal_length
$_->{'name'} eq 'diagonal_length'
? ()
: do {
my $value = $path->{$_->{'name'}};
if ($_->{'type'} eq 'boolean') {
$value = ($value ? 1 : 0);
}
### $_
### $value
### gives: "$_->{'name'}=$value"
(defined $value ? "$_->{'name'}=$value" : ())
}
}
_planepath_oeis_anum_parameter_info_list($path)));
}
sub _planepath_oeis_anum_parameter_info_list {
my ($path) = @_;
my @parameter_info_list = $path->_NumSeq_override_parameter_info_list;
unless (@parameter_info_list) {
@parameter_info_list = ($path->parameter_info_list,
$path->_NumSeq_extra_parameter_info_list);
}
return @parameter_info_list;
}
#------------------------------------------------------------------------------
sub new {
my $self = shift->SUPER::new(@_);
my $planepath_object = ($self->{'planepath_object'}
||= _planepath_name_to_object($self->{'planepath'}));
### coordinate func: '_coordinate_func_'.$self->{'coordinate_type'}
{
my $key = $self->{'coordinate_type'};
$key =~ s{/}{div};
$self->{'coordinate_func'}
= $planepath_object->can("_NumSeq_Coord_${key}_func")
|| $self->can("_coordinate_func_$key")
|| croak "Unrecognised coordinate_type: ",$self->{'coordinate_type'};
}
$self->rewind;
### $self
return $self;
}
sub _planepath_name_to_object {
my ($name) = @_;
### PlanePathCoord _planepath_name_to_object(): $name
($name, my @args) = split /,+/, $name;
$name = "Math::PlanePath::$name";
### $name
require Module::Load;
Module::Load::load ($name);
return $name->new (map {/(.*?)=(.*)/} @args);
# width => $options{'width'},
# height => $options{'height'},
}
sub default_i_start {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'}
# nasty hack allow no 'planepath_object' when SUPER::new() calls rewind()
|| return 0;
return $planepath_object->n_start;
}
sub i_start {
my ($self) = @_;
return (defined $self->{'i_start'}
? $self->{'i_start'}
# nasty hack allow no 'planepath_object' when SUPER::new() calls
# rewind()
: $self->{'planepath_object'} &&
$self->{'planepath_object'}->n_start);
}
sub rewind {
my ($self) = @_;
$self->{'i'} = $self->i_start;
}
sub next {
my ($self) = @_;
### NumSeq-PlanePathCoord next(): "i=$self->{'i'}"
my $i = $self->{'i'}++;
if (defined (my $value = &{$self->{'coordinate_func'}}($self, $i))) {
return ($i, $value);
} else {
return;
}
}
sub ith {
my ($self, $i) = @_;
### NumSeq-PlanePathCoord ith(): $i
return &{$self->{'coordinate_func'}}($self,$i);
}
use constant _INFINITY => do {
my $x = 999;
foreach (1 .. 20) {
$x *= $x;
}
$x;
};
sub _coordinate_func_X {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x;
}
sub _coordinate_func_Y {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $y;
}
sub _coordinate_func_AbsX {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return abs($x);
}
sub _coordinate_func_AbsY {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return abs($y);
}
sub _coordinate_func_Sum {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x + $y;
}
sub _coordinate_func_SumAbs {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return abs($x) + abs($y);
}
sub _coordinate_func_Product {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x * $y;
}
sub _coordinate_func_DiffXY {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x - $y;
}
sub _coordinate_func_DiffXYdiv2 {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return ($x - $y) / 2;
}
sub _coordinate_func_DiffYX {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $y - $x;
}
sub _coordinate_func_AbsDiff {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return abs($x - $y);
}
sub _coordinate_func_Radius {
my ($self, $n) = @_;
return $self->{'planepath_object'}->n_to_radius($n);
}
sub _coordinate_func_RSquared {
my ($self, $n) = @_;
return $self->{'planepath_object'}->n_to_rsquared($n);
}
sub _coordinate_func_DiffXYsquares {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x*$x - $y*$y;
}
sub _coordinate_func_DiffYXsquares {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $y*$y - $x*$x;
}
sub _coordinate_func_TRadius {
my $rsquared;
return (defined ($rsquared = _coordinate_func_TRSquared(@_))
? sqrt($rsquared)
: undef);
}
sub _coordinate_func_TRSquared {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return $x*$x + 3*$y*$y;
}
sub _coordinate_func_Depth {
my ($self, $n) = @_;
return $self->{'planepath_object'}->tree_n_to_depth($n);
}
sub _coordinate_func_NumChildren {
my ($self, $n) = @_;
return $self->{'planepath_object'}->tree_n_num_children($n);
}
sub _coordinate_func_IsLeaf {
my ($self, $n) = @_;
### _coordinate_func_IsLeaf(): $n
my $num_children = $self->{'planepath_object'}->tree_n_num_children($n);
# undef, 0 or 1
return (defined $num_children ? ($num_children == 0 ? 1 : 0) : undef);
}
sub _coordinate_func_IsNonLeaf {
my ($self, $n) = @_;
### _coordinate_func_IsLeaf(): $n
my $num_children = $self->{'planepath_object'}->tree_n_num_children($n);
# undef, 0 or 1
return (defined $num_children ? ($num_children == 0 ? 0 : 1) : undef);
}
use Math::PlanePath::GcdRationals;
use POSIX 'fmod';
sub _coordinate_func_GCD {
my ($self, $n) = @_;
# FIXME: Maybe re-run with bigrat if X or Y not integers.
if ($self->{'planepath_object'}->isa('Math::PlanePath::KochSnowflakes')
&& $n <= 3) {
return 1/3;
}
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
$x = abs($x);
$y = abs($y);
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
if ($x == int($x) && $y == int($y)) {
return Math::PlanePath::GcdRationals::_gcd($x,$y);
}
if ($x == 0) {
return $y;
}
if ($y > $x) {
$y = fmod($y,$x);
}
for (;;) {
### assert: $x >= 1
if ($y == 0) {
return $x; # gcd(x,0)=x
}
if ($y < 0.00001) {
return 0;
}
($x,$y) = ($y, fmod($x,$y));
}
}
sub _coordinate_func_GcdDivisions {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
$x = abs(int($x));
$y = abs(int($y));
if ($x == 0) {
return $y;
}
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
if ($x < $y) { ($x,$y) = ($y,$x); }
my $count = 0;
for (;;) {
if ($y <= 1) {
return $count;
}
($x,$y) = ($y, $x % $y);
$count++;
}
}
#------------------------------------------------------------------------------
# UNTESTED/EXPERIMENTAL
# A215200 Triangle read by rows, Kronecker symbol (n-k|k) for n>=1, 1<=k<=n.
# cf A005825 Numerators in a worst case of a Jacobi symbol algorithm.
# A005826 Worst case of a Jacobi symbol algorithm.
# A005827 Worst case of a Jacobi symbol algorithm.
# A157415 Triangle t(n,m) = Jacobi(prime(n) / prime(m)) + Jacobi( prime(n)/ prime(n-m+2)), 2<=m<=n.
sub _coordinate_func_KroneckerSymbol {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return _kronecker_symbol($x,$y);
}
sub _kronecker_symbol {
my ($x, $y) = @_;
### _kronecker_symbol(): "x=$x y=$y"
$x = int($x);
$y = int($y);
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
if ($x == 0) {
# (0/b)=1 if b=+/-1, (0/b)=0 otherwise
return ($y == 1 || $y == -1 ? 1 : 0);
}
if ($y == 0) {
# (a/0)=1 if a=+/-1, (a/0)=0 otherwise
return ($x == 1 || $x == -1 ? 1 : 0);
}
my $ret = 0;
# (a/-1)=1 if a>=0, (a/-1)=-1 if a<0
if ($y < 0) {
$y = abs($y);
if ($x < 0) {
### (a/-1) = -1 when a<0 ...
$ret = 2;
}
}
if ($y % 2 == 0) {
if ($x % 2 == 0) {
return 0; # (even/even)=0
}
# (a/2) = (2/a)
while ($y && $y % 4 == 0) { # (a/2)*(a/2)=1
### initial y multiple of 4 ...
$y /= 4;
}
# (b/2)=(2/b) for b odd
# (2/b) = (-1)^((b^2-1)/8) which is 1 if b==1,7mod8 or -1 if b==3,5mod8
if ($y % 2 == 0) {
### initial y even, xor: (($x+1)/2) & 2
### assert: $x % 2 != 0
$ret ^= ($x+1)/2;
$y /= 2;
}
}
for (;;) {
### at: "x=$x y=$y"
### assert: $y%2 != 0
if ($y <= 1) {
### y=1 stop (a/1)=1 ...
last;
}
### assert: $y > 1
$x %= $y;
### remainder to: "x=$x"
if ($x <= 1) {
### stop, (1/b) = 1 ...
last;
}
# (2/b) with b odd is (-1)^((b^2-1)/8)
# is (2/b)=1 if b==1,7mod8 or (2/b)=-1 if b==3,5mod8
while ($x && $x % 4 == 0) {
### x multiple of 4 ...
$x /= 4;
}
if ($x % 2 == 0) {
# (2/b) = (-1)^((b^2-1)/8) which is 1 if b==1,7mod8 or -1 if b==3,5mod8
### x even, xor: (($y+1)/2) & 2
$ret ^= ($y+1)/2;
$x /= 2;
}
### reciprocity, xor: ($x % 4) & ($y % 4) & 2
$ret ^= ($x % 4) & ($y % 4);
($x,$y) = ($y,$x);
}
if ($x == 0) {
### (0/b)=0 ...
return 0;
}
### final ret: ($ret & 2)
return ($ret & 2 ? -1 : 1);
}
sub _coordinate_func_NumSiblings {
my ($self, $n) = @_;
return path_tree_n_num_siblings($self->{'planepath_object'}, $n);
}
# ENHANCE-ME: if $n==NaN would like to return NaN, maybe
sub path_tree_n_num_siblings {
my ($path, $n) = @_;
$n = $path->tree_n_parent($n);
return (defined $n
? $path->tree_n_num_children($n) - 1 # not including self
: 0); # any tree root considered to have no siblings
}
sub _coordinate_func_RootN {
my ($self, $n) = @_;
return $self->{'planepath_object'}->tree_n_root($n);
}
sub _coordinate_func_LeafDistance {
my ($self, $n) = @_;
if (my $coderef = $self->{'planepath_object'}
->can('_EXPERIMENTAL__tree_n_to_leafdist')) {
return $self->{'planepath_object'}->$coderef($n);
}
return path_tree_n_to_leafdist_by_search($self->{'planepath_object'},$n);
}
sub path_tree_n_to_leafdist_by_search {
my ($path, $n) = @_;
### path_tree_n_to_leafdist(): $n
if ($n < $path->n_start || ! $path->tree_any_leaf($path)) {
return undef;
}
if (is_infinite($n)) {
return $n;
}
my @pending = ($n);
for (my $distance = 0; ; $distance++) {
### $distance
### @pending
@pending = map {
my @children = $path->tree_n_children($_)
or return $distance;
### @children
@children
} @pending;
}
}
# math-image --values=PlanePathCoord,coordinate_type=SubHeight,planepath=ThisPath --path=SierpinskiTriangle --scale=10
sub _coordinate_func_SubHeight {
my ($self, $n) = @_;
### _coordinate_func_SubHeight(): $n
my $height = $self->{'planepath_object'}->tree_n_to_subheight($n);
return (defined $height ? $height : _INFINITY);
}
# math-image --values=PlanePathCoord,coordinate_type=NumSurround4,planepath=DragonCurve --path=DragonCurve --scale=10
{
my $surround = [ 1,0, 0,1, -1,0, 0,-1 ];
sub _coordinate_func_NumSurround4 {
my ($self, $n) = @_;
return _path_n_surround_count ($self->{'planepath_object'}, $n, $surround);
}
}
{
my $surround = [ 1,1, -1,1, -1,-1, 1,-1 ];
sub _coordinate_func_NumSurround4d {
my ($self, $n) = @_;
return _path_n_surround_count ($self->{'planepath_object'}, $n, $surround);
}
}
{
my $surround = [ 2,0, 1,1, -1,1,
-2,0, -1,-1, 1,-1 ];
sub _coordinate_func_NumSurround6 {
my ($self, $n) = @_;
return _path_n_surround_count ($self->{'planepath_object'}, $n, $surround);
}
}
{
my $surround = [ 1,0, 0,1, -1,0, 0,-1,
1,1, -1,1, 1,-1, -1,-1 ];
sub _coordinate_func_NumSurround8 {
my ($self, $n) = @_;
return _path_n_surround_count ($self->{'planepath_object'}, $n, $surround);
}
}
sub _path_n_surround_count {
my ($path, $n, $surround_aref) = @_;
# my $aref = $surround[$num_points]
# || croak "_path_n_surround_count() unrecognised number of points ",$num_points;
my ($x, $y) = $path->n_to_xy($n) or return undef;
my $count = 0;
for (my $i = 0; $i < @$surround_aref; $i+=2) {
$count += $path->xy_is_visited($x + $surround_aref->[$i],
$y + $surround_aref->[$i+1]);
}
return $count;
}
# rounding towards zero
sub _coordinate_func_IntXY {
my ($self, $n) = @_;
### _coordinate_func_IntXY(): $n
if (my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)) {
return _xy_to_IntXY($x,$y);
}
return undef;
}
sub _xy_to_IntXY {
my ($x, $y) = @_;
### xy: "x=$x y=$y"
if ($y < 0) {
$y = -$y;
$x = -$x;
}
if ($y == 0) {
return _INFINITY; # X/0 = infinity
}
if ($y == int($y)) {
### done in integers, no floating point ...
my $r = $x % $y;
### $r
if ($x < 0 && $r > 0) {
$r -= $y;
}
### assert: (($x>=0)&&($r>=0)) || (($x<=0)&&($r<=0))
$x -= $r;
### assert: ($x % $y) == 0
return int($x / $y);
}
return int($x/$y);
}
sub _coordinate_func_FracXY {
my ($self, $n) = @_;
### _coordinate_func_FracXY(): $n
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
### xy: "x=$x y=$y"
if ($y < 0) {
$y = -$y;
$x = -$x;
}
if ($y == 0) {
return 0; # X/0 = infinity + frac=0
}
if ($y == int($y)) {
### done in integers ...
my $r = $x % $y;
if ($x < 0 && $r > 0) {
$r -= $y;
}
# EXPERIMENTAL:
# bigint/bigint as bigrat, otherwise promote to bigfloat
if (ref $r && $r->isa('Math::BigInt')) {
if (ref $y && $y->isa('Math::BigInt')) {
require Math::BigRat;
return Math::BigRat->new($r) / $y;
}
$r = $r->as_float;
} else {
if (ref $y && $y->isa('Math::BigInt')) { $y = $y->as_float; }
}
return $r/$y;
} else {
my $f = $x/$y;
return $f - int($x/$y);
}
}
# Math::BigInt in perl 5.6.0 has and/or/xor
sub _op_and { $_[0] & $_[1] }
sub _op_or { $_[0] | $_[1] }
sub _op_xor { $_[0] ^ $_[1] }
sub _coordinate_func_BitAnd {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return _bitwise_by_parts($x,$y, \&_op_and);
}
sub _coordinate_func_BitOr {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return _bitwise_by_parts($x,$y, \&_op_or);
}
sub _coordinate_func_BitXor {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return _bitwise_by_parts($x,$y, \&_op_xor);
}
use constant 1.02 _UV_MAX_PLUS_1 => do {
my $pow = 1.0;
my $uv = ~0;
while ($uv) {
$uv >>= 1;
$pow *= 2.0;
}
$pow
};
sub _bitwise_by_parts {
my ($x, $y, $opfunc) = @_;
### _bitwise_by_parts(): $x, $y
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
# Positive integers in UV range plain operator.
# Any ref is Math::BigInt or whatever left to its operator overloads.
if (ref $x || ref $y
|| ($x == int($x) && $y == int($y)
&& $x >= 0 && $y >= 0
&& $x < _UV_MAX_PLUS_1 && $x < _UV_MAX_PLUS_1)) {
return &$opfunc($x,$y);
}
$x *= 65536.0;
$x *= 65536.0;
$x = int($x);
$y *= 65536.0;
$y *= 65536.0;
$y = int($y);
my @ret; # low to high
while ($x >= 1 || $x < -1 || $y >= 1 || $y < -1) {
### $x
### $y
my $xpart = $x % 65536.0;
if ($xpart < 0) { $xpart += 65536.0; }
$x = ($x - $xpart) / 65536.0;
my $ypart = $y % 65536.0;
if ($ypart < 0) { $ypart += 65536.0; }
$y = ($y - $ypart) / 65536.0;
### xpart: $xpart . sprintf(' %04X',$xpart)
### ypart: $ypart . sprintf(' %04X',$ypart)
push @ret, &$opfunc($xpart,$ypart);
}
my $ret = (&$opfunc($x<0,$y<0) ? -1 : 0);
### @ret
### $x
### $y
### $ret
foreach my $rpart (reverse @ret) { # high to low
$ret = 65536.0*$ret + $rpart;
}
### ret joined: $ret
$ret /= 65536.0;
$ret /= 65536.0;
### ret final: $ret
return $ret;
}
use constant 1.02 _IV_MIN => - (~0 >> 1) - 1;
sub _sign_extend {
my ($n) = @_;
return ($n - (- _IV_MIN)) + _IV_MIN;
}
use constant 1.02 _UV_NUMBITS => do {
my $uv = ~0;
my $count = 0;
while ($uv) {
$uv >>= 1;
$count++;
last if $count >= 1024;
}
$count
};
sub _frac_to_int {
my ($x) = @_;
$x -= int($x);
return int(abs($x)*(2**_UV_NUMBITS()));
}
sub _int_to_frac {
my ($x) = @_;
return $x / (2**_UV_NUMBITS());
}
sub _coordinate_func_Min {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return min($x,$y);
}
sub _coordinate_func_Max {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return max($x,$y);
}
sub _coordinate_func_MinAbs {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return min(abs($x),abs($y));
}
sub _coordinate_func_MaxAbs {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return max(abs($x),abs($y));
}
sub _coordinate_func_MaxAbsTri {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return max(abs($x+$y),abs($x-$y),abs(2*$y));
}
sub _coordinate_func_MinAbsTri {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
return min(abs($x+$y),abs($x-$y),abs(2*$y));
}
use Math::PlanePath::GcdRationals;
sub _coordinate_func_MulDist {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
$x = int(abs($x));
$y = int(abs($y));
if (my $g = Math::PlanePath::GcdRationals::_gcd($x,$y)) {
$x /= $g;
$y /= $g;
}
unless ($x < (2.0**32) && $y < (2.0**32)) {
return undef;
}
require Math::Factor::XS;
return Math::Factor::XS::count_prime_factors($x) + Math::Factor::XS::count_prime_factors($y);
}
# Count of differing bit positions.
# Infinite if twos-comp negative.
# 1111 -1 1
# 1101 -2 10
# 1110 -3 11
#
use Math::PlanePath::Base::Digits
'bit_split_lowtohigh';
sub _coordinate_func_HammingDist {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
# twos complement
if ($x<0) {
if ($y >= 0) { return _INFINITY; }
$x = -$x;
$y = -$y;
} else {
if ($y < 0) { return _INFINITY; }
}
# abs values
# $x = abs(int($x));
# $y = abs(int($y));
my @xbits = bit_split_lowtohigh($x);
my @ybits = bit_split_lowtohigh($y);
my $ret = 0;
while (@xbits || @ybits) {
$ret += (shift @xbits ? 1 : 0) ^ (shift @ybits ? 1 : 0);
}
return $ret;
}
sub _coordinate_func_Parity {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
$x += $y;
$y = _floor($x);
$y -= ($y % 2);
return $x - $y;
}
sub _floor {
my ($x) = @_;
my $int = int($x);
return ($x < $int ? $int-1 : $int);
}
sub _coordinate_func_Numerator {
my ($self, $n) = @_;
### _coordinate_func_Numerator(): $n
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
### $x
### $y
if ($y < 0) { $x = -$x; }
if (is_infinite($x)) { return $x; }
if (is_infinite($y)) { return $y; }
my $g = Math::PlanePath::GcdRationals::_gcd(abs($x),abs($y));
return ($g == 0
? 0 :
$x/$g);
}
sub _coordinate_func_Denominator {
my ($self, $n) = @_;
my ($x, $y) = $self->{'planepath_object'}->n_to_xy($n)
or return undef;
if ($y < 0) {
$x = -$x;
$y = -$y;
}
if ($y == 0) {
# +-any/0 reckoned as 1/0
return $y;
}
if (is_infinite($x)) {
return $x; # +-inf/nonzero = +-inf
}
if ($x == 0 # 0/nonzero reckoned as 0/1
|| is_infinite($y)) { # +-finite/+inf reckoned as 0/1
return 1;
}
my $g = Math::PlanePath::GcdRationals::_gcd(abs($x),$y);
if ($g == 0) {
# X/0 reckoned as 1/0
return 0;
}
return abs($y)/$g;
}
#------------------------------------------------------------------------------
sub characteristic_integer {
my ($self) = @_;
### PlanePathCoord characteristic_integer() ...
my $planepath_object = $self->{'planepath_object'};
if (my $func = $planepath_object->can("_NumSeq_Coord_$self->{'coordinate_type'}_integer")) {
return $planepath_object->$func();
}
if (defined (my $values_min = $self->values_min)
&& defined (my $values_max = $self->values_max)) {
if ($values_min == int($values_min)
&& $values_max == int($values_max)
&& $values_min == $values_max) {
return 1;
}
}
return undef;
}
sub characteristic_smaller {
my ($self) = @_;
### characteristic_smaller() ...
my $planepath_object = $self->{'planepath_object'};
my $func;
return
(($func = ($planepath_object->can("_NumSeq_Coord_$self->{'coordinate_type'}_smaller")))
? $planepath_object->$func()
: 1); # default is smaller
}
{
my %coordinate_to_d_minimum_method
= (X => 'dx_minimum',
Y => 'dy_minimum',
Sum => 'dsumxy_minimum',
DiffXY => 'ddiffxy_minimum',
DiffYX => \&path_ddiffyx_minimum,
);
sub path_ddiffyx_minimum {
my ($path) = @_;
my $ddiffxy_maximum = $path->ddiffxy_maximum();
return (defined $ddiffxy_maximum ? - $ddiffxy_maximum : undef);
}
my %coordinate_type_monotonic_use
= (RSquared => 'Radius',
TRSquared => 'TRadius',
);
sub characteristic_increasing {
my ($self) = @_;
### PlanePathCoord characteristic_increasing() ...
my $planepath_object = $self->{'planepath_object'};
my $coordinate_type = $self->{'coordinate_type'};
# eg. if dx_minimum() > 0 then X is increasing
if (my $method = $coordinate_to_d_minimum_method{$coordinate_type}) {
my $d_minimum = $planepath_object->$method();
### delta method: $method
### $d_minimum
return (defined $d_minimum && $d_minimum > 0);
}
$coordinate_type = ($coordinate_type_monotonic_use{$coordinate_type}
|| $coordinate_type);
if (my $coderef = $planepath_object->can("_NumSeq_Coord_${coordinate_type}_increasing")) {
### dispatch to: $coderef
return $planepath_object->$coderef();
}
### unknown ...
return undef;
}
sub characteristic_non_decreasing {
my ($self) = @_;
### PlanePathCoord characteristic_non_decreasing() ...
my $planepath_object = $self->{'planepath_object'};
my $coordinate_type = $self->{'coordinate_type'};
# eg. if dx_minimum() >= 0 then X is non-decreasing
if (my $method = $coordinate_to_d_minimum_method{$coordinate_type}) {
my $d_minimum = $planepath_object->$method();
### delta method: $method
### $d_minimum
return (defined $d_minimum && $d_minimum >= 0);
}
if (defined (my $values_min = $self->values_min)) {
if (defined (my $values_max = $self->values_max)) {
if ($values_min == $values_max) {
### constant seq is non-decreasing ...
return 1;
}
}
}
$coordinate_type = ($coordinate_type_monotonic_use{$coordinate_type}
|| $coordinate_type);
if (my $coderef = $planepath_object->can("_NumSeq_Coord_${coordinate_type}_non_decreasing")) {
### dispatch to: $coderef
return $planepath_object->$coderef();
}
### if increasing then non_decreasing too ...
return $self->characteristic_increasing;
}
}
{
my %values_min = (X => 'x_minimum',
Y => 'y_minimum',
Sum => 'sumxy_minimum',
SumAbs => 'sumabsxy_minimum',
DiffXY => 'diffxy_minimum',
AbsDiff => 'absdiffxy_minimum',
RSquared => 'rsquared_minimum',
GCD => 'gcdxy_minimum',
NumChildren => 'tree_num_children_minimum',
);
sub values_min {
my ($self) = @_;
### PlanePathCoord values_min() ...
my $planepath_object = $self->{'planepath_object'};
if (my $method = ($values_min{$self->{'coordinate_type'}}
|| $planepath_object->can("_NumSeq_Coord_$self->{'coordinate_type'}_min"))) {
### $method
return $planepath_object->$method();
}
return undef;
}
}
{
my %values_max = (X => 'x_maximum',
Y => 'y_maximum',
Sum => 'sumxy_maximum',
SumAbs => 'sumabsxy_maximum',
DiffXY => 'diffxy_maximum',
AbsDiff => 'absdiffxy_maximum',
GCD => 'gcdxy_maximum',
NumChildren => 'tree_num_children_maximum',
);
sub values_max {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $method = ($values_max{$self->{'coordinate_type'}}
|| $planepath_object->can("_NumSeq_Coord_$self->{'coordinate_type'}_max"))) {
return $planepath_object->$method();
}
return undef;
}
}
{ package Math::PlanePath;
use constant _NumSeq_override_parameter_info_list => ();
use constant _NumSeq_extra_parameter_info_list => ();
use constant _NumSeq_Coord_NumSurround4_min => 0;
use constant _NumSeq_Coord_NumSurround6_min => 0;
use constant _NumSeq_Coord_NumSurround8_min => 0;
use constant _NumSeq_Coord_NumSurround4 => 4;
use constant _NumSeq_Coord_NumSurround6 => 6;
use constant _NumSeq_Coord_NumSurround8 => 8;
use constant _NumSeq_Coord_NumSurround4_integer => 1; # always integers
use constant _NumSeq_Coord_NumSurround6_integer => 1;
use constant _NumSeq_Coord_NumSurround8_integer => 1;
use constant _NumSeq_Coord_oeis_anum => {};
#------
# X
use constant _NumSeq_Coord_X_integer => 1; # usually
use constant _NumSeq_Coord_X_increasing => undef;
use constant _NumSeq_Coord_X_non_decreasing => undef;
#------
# Y
use constant _NumSeq_Coord_Y_integer => 1; # usually
use constant _NumSeq_Coord_Y_increasing => undef;
use constant _NumSeq_Coord_Y_non_decreasing => undef;
#------
# Sum
sub _NumSeq_Coord_Sum_integer {
my ($self) = @_;
### _NumSeq_Coord_Sum_integer() ...
return ($self->_NumSeq_Coord_X_integer
&& $self->_NumSeq_Coord_Y_integer);
}
*_NumSeq_Coord_SumAbs_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_Product_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_DiffXY_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_AbsDiff_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_RSquared_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_TRSquared_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_DiffXYsquares_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_DiffYXsquares_integer = \&_NumSeq_Coord_Sum_integer;
sub _NumSeq_Coord_Product_min {
my ($self) = @_;
my ($x_minimum, $y_minimum);
if (defined ($x_minimum = $self->x_minimum)
&& defined ($y_minimum = $self->y_minimum)
&& $x_minimum >= 0
&& $y_minimum >= 0) {
return $x_minimum * $y_minimum;
}
return undef;
}
sub _NumSeq_Coord_Product_max {
my ($self) = @_;
my ($x_max, $y_minimum);
### X_max: $self->x_maximum
### Y_min: $self->y_minimum
if (defined ($x_max = $self->x_maximum)
&& defined ($y_minimum = $self->y_minimum)
&& $x_max <= 0
&& $y_minimum >= 0) {
# X all negative, Y all positive
return $y_minimum * $x_max;
}
return undef;
}
#----------
# DiffYX opposite of DiffXY
sub _NumSeq_Coord_DiffYX_min {
my ($self) = @_;
if (defined (my $m = $self->diffxy_maximum)) {
return - $m;
} else {
return undef;
}
}
sub _NumSeq_Coord_DiffYX_max {
my ($self) = @_;
if (defined (my $m = $self->diffxy_minimum)) {
return - $m;
} else {
return undef;
}
}
sub _NumSeq_Coord_DiffYX_integer {
my ($self) = @_;
return $self->_NumSeq_Coord_DiffXY_integer;
}
#----------
# Radius
sub _NumSeq_Coord_Radius_min {
my ($path) = @_;
return sqrt($path->rsquared_minimum);
}
sub _NumSeq_Coord_Radius_max {
my ($path) = @_;
my $rsquared_maximum = $path->rsquared_maximum;
return (defined $rsquared_maximum ? sqrt($rsquared_maximum) : undef);
}
#----------
# TRadius
sub _NumSeq_Coord_TRadius_min {
my ($path) = @_;
return sqrt($path->_NumSeq_Coord_TRSquared_min);
}
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
# The X and Y each closest to the origin. This assumes that point is
# actually visited, but is likely to be close.
my $x_minimum = $self->x_minimum;
my $x_maximum = $self->x_maximum;
my $y_minimum = $self->y_minimum;
my $y_maximum = $self->y_maximum;
my $x = (( defined $x_minimum && $x_minimum) > 0 ? $x_minimum
: (defined $x_maximum && $x_maximum) < 0 ? $x_maximum
: 0);
my $y = (( defined $y_minimum && $y_minimum) > 0 ? $y_minimum
: (defined $y_maximum && $y_maximum) < 0 ? $y_maximum
: 0);
return ($x*$x + 3*$y*$y);
}
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
if (defined(my $x = $self->x_minimum)
&& defined(my $y = $self->y_minimum)) {
if ($y >= 0) {
if ($y == 0) {
$y = 1;
}
if ($x >= 0 && $y <= $x) {
$y = 2*$x;
if (defined (my $y_maximum = $self->y_maximum)) {
$y = List::Util::min($y, $y_maximum);
}
}
### using: "x=$x y=$y"
# presume that point x_minimum(),y_minimum() occurs
return Math::NumSeq::PlanePathCoord::_xy_to_IntXY($x,$y);
}
}
return undef;
}
use constant _NumSeq_Coord_IntXY_max => undef;
use constant _NumSeq_Coord_IntXY_integer => 1;
use constant _NumSeq_Coord_FracXY_max => 1;
use constant _NumSeq_FracXY_max_is_supremum => 1;
sub _NumSeq_Coord_FracXY_min {
my ($self) = @_;
if (! $self->x_negative && ! $self->y_negative) {
return 0;
} else {
return -1;
}
}
*_NumSeq_FracXY_min_is_infimum = \&_NumSeq_Coord_FracXY_min; # if non-zero
use constant _NumSeq_Coord_FracXY_integer => 0;
use constant _NumSeq_Coord_Parity_min => 0;
sub _NumSeq_Coord_Parity_integer { $_[0]->_NumSeq_Coord_Sum_integer }
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->_NumSeq_Coord_Parity_integer
? 1
: 2);
}
sub _NumSeq_Parity_max_is_supremum {
my ($self) = @_;
return ($self->_NumSeq_Coord_Parity_integer ? 0 : 1);
}
sub _NumSeq_Coord_Numerator_min {
my ($self) = @_;
if (defined (my $gcd_maximum = $self->gcdxy_maximum)) {
if ($gcd_maximum == 1) {
return $self->x_minimum; # X,Y no common factor, so Numerator==X
}
}
if (! $self->y_negative
&& defined (my $x_minimum = $self->x_minimum)) {
### $x_minimum
if ($x_minimum >= 1) {
return 1; # somewhere X/Y dividing out to 1/Z
}
if ($x_minimum >= 0) {
return 0; # 0/Y
}
}
return undef;
}
use constant _NumSeq_Coord_Numerator_integer => 1;
sub _NumSeq_Coord_Denominator_min {
my ($self) = @_;
if (defined (my $y_minimum = $self->y_minimum)) {
if ($y_minimum > 0) {
return 1; # X/0=1/0 doesn't occur, so den>=1
}
if ($y_minimum == 0) {
return 0; # X/0=1/0
}
}
return 0;
}
use constant _NumSeq_Coord_Denominator_integer => 1;
# fractional part treated bitwise
*_NumSeq_Coord_BitAnd_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_BitOr_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_BitXor_integer = \&_NumSeq_Coord_Sum_integer;
#-------------
# GCD
use constant _NumSeq_Coord_GCD_integer => 1;
use constant _NumSeq_Coord_GcdDivisions_min => 0;
use constant _NumSeq_Coord_GcdDivisions_max => undef;
use constant _NumSeq_Coord_GcdDivisions_integer => 1;
#-------------
use constant _NumSeq_Coord_KroneckerSymbol_min => -1;
use constant _NumSeq_Coord_KroneckerSymbol_max => 1;
use constant _NumSeq_Coord_KroneckerSymbol_integer => 1;
sub _NumSeq_Coord_BitAnd_min {
my ($self) = @_;
# if one of X,Y always >=0 then BitAnd >= 0
my $max_min = $self->_NumSeq_Coord_Max_min;
if (defined $max_min && $max_min >= 0) {
return 0;
}
return undef;
}
sub _NumSeq_Coord_BitOr_min {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
my $y_minimum = $self->y_minimum;
if (defined $x_minimum && defined $y_minimum) {
return ($x_minimum > 0
? ($y_minimum > 0
? List::Util::min($x_minimum, $y_minimum) # +X,+Y
: $x_minimum) # +X,-Y
: ($y_minimum > 0
? $y_minimum # -X,+Y
: List::Util::min($x_minimum, $y_minimum))); # -X,-Y
} else {
return undef;
}
}
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
my $y_minimum = $self->y_minimum;
if ($self->x_negative || $self->y_negative) {
return undef;
} else {
return 0; # no negatives
}
}
#-------------
# Min
# Return the minimum value taken by min(X,Y) at integer N.
# This is simply the smaller of x_minimum() or y_minimum().
# If either X or Y is unbounded below then min(X,Y) is unbounded below too
# and minxy_minimum() returns undef.
#
sub _NumSeq_Coord_Min_min {
my ($self) = @_;
# min(X,Y) has a minimum iff both X and Y have a minimum.
if (defined (my $x_minimum = $self->x_minimum)
&& defined (my $y_minimum = $self->y_minimum)) {
return Math::NumSeq::PlanePathCoord::min($x_minimum, $y_minimum);
}
return undef;
}
sub _NumSeq_Coord_Min_max {
my ($self) = @_;
# If there's a maximum X or Y then that will be the maximum for Min.
# If there's both maximum X and Y then the bigger of the two.
my $x_maximum = $self->x_maximum;
my $y_maximum = $self->y_maximum;
if (defined $x_maximum || defined $y_maximum) {
return Math::NumSeq::PlanePathCoord::max
(defined $x_maximum ? $x_maximum : (),
defined $y_maximum ? $y_maximum : ());
}
return undef;
}
#-------------
# Max
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
my $x_minimum = $self->x_minimum;
my $y_minimum = $self->y_minimum;
# or empty max is undef if neither minimum
return Math::NumSeq::PlanePathCoord::max
(defined $x_minimum ? $x_minimum : (),
defined $y_minimum ? $y_minimum : ());
}
# Return the maximum value taken by max(X,Y) at integer N.
# This is simply the smaller of x_maximum() or y_maximum().
# If either X or Y is unbounded above then max(X,Y) is unbounded above too
# and maxxy_maximum() returns undef.
#
sub _NumSeq_Coord_Max_max {
my ($self) = @_;
if (defined (my $x_maximum = $self->x_maximum)
&& defined (my $y_maximum = $self->y_maximum)) {
return Math::NumSeq::PlanePathCoord::max($x_maximum, $y_maximum);
}
return undef;
}
*_NumSeq_Coord_Min_integer = \&_NumSeq_Coord_Sum_integer;
*_NumSeq_Coord_Max_integer = \&_NumSeq_Coord_Sum_integer;
sub _NumSeq_Coord_Max_is_always_X {
my ($path) = @_;
# if X-Y>=0 then X>=Y and max(X,Y)=X
my $diffxy_minimum = $path->diffxy_minimum;
return (defined $diffxy_minimum && $diffxy_minimum >= 0);
}
sub _NumSeq_Coord_Max_is_always_Y {
my ($path) = @_;
# if X-Y<=0 then X<=Y and max(X,Y)=Y
my $diffxy_maximum = $path->diffxy_maximum;
return (defined $diffxy_maximum && $diffxy_maximum <= 0);
}
sub _NumSeq_Coord_Max_increasing {
my ($path) = @_;
if ($path->_NumSeq_Coord_Max_is_always_X) {
return $path->_NumSeq_Coord_X_increasing;
}
if ($path->_NumSeq_Coord_Max_is_always_Y) {
return $path->_NumSeq_Coord_Y_increasing;
}
return undef;
}
sub _NumSeq_Coord_Max_non_decreasing {
my ($path) = @_;
if ($path->_NumSeq_Coord_Max_is_always_X) {
return $path->_NumSeq_Coord_X_non_decreasing;
}
if ($path->_NumSeq_Coord_Max_is_always_Y) {
return $path->_NumSeq_Coord_Y_non_decreasing;
}
return undef;
}
#------------
# HammingDist
use constant _NumSeq_Coord_HammingDist_min => 0;
use constant _NumSeq_Coord_HammingDist_integer => 1;
# sub _NumSeq_Coord_HammingDist_min {
# my ($self) = @_;
# return ($self->x_negative || $self->y_negative ? undef : 0);
# }
#-------------
# MinAbs
sub _NumSeq_Coord_MinAbs_min {
my ($self) = @_;
return Math::NumSeq::PlanePathCoord::min
($self->_NumSeq_Coord_AbsX_min,
$self->_NumSeq_Coord_AbsY_min);
}
sub _NumSeq_Coord_MinAbs_max {
my ($self) = @_;
my $absx_maximum = $self->_NumSeq_Coord_AbsX_max;
my $absy_maximum = $self->_NumSeq_Coord_AbsY_max;
# smaller of the two maxima, or undef if neither bounded
return Math::NumSeq::PlanePathCoord::min
((defined $absx_maximum ? $absx_maximum : ()),
(defined $absy_maximum ? $absy_maximum : ()));
}
*_NumSeq_Coord_MinAbs_integer = \&_NumSeq_Coord_Sum_integer;
sub _NumSeq_Coord_MaxAbs_non_decreasing {
my ($path) = @_;
if (! $path->x_negative && ! $path->y_negative) {
# X>0 and Y>0 so MaxAbs==Max
return $path->_NumSeq_Coord_Max_non_decreasing;
}
return undef;
}
sub _NumSeq_Coord_MaxAbs_increasing {
my ($path) = @_;
if (! $path->x_negative && ! $path->y_negative) {
# X>0 and Y>0 so MaxAbs==Max
return $path->_NumSeq_Coord_Max_increasing;
}
return undef;
}
#-------------
# MaxAbs
sub _NumSeq_Coord_MaxAbs_min {
my ($self) = @_;
return Math::NumSeq::PlanePathCoord::max
($self->_NumSeq_Coord_AbsX_min,
$self->_NumSeq_Coord_AbsY_min);
}
sub _NumSeq_Coord_MaxAbs_max {
my ($self) = @_;
if (defined (my $x_minimum = $self->x_minimum)
&& defined (my $y_minimum = $self->y_minimum)
&& defined (my $x_maximum = $self->x_maximum)
&& defined (my $y_maximum = $self->y_maximum)) {
return Math::NumSeq::PlanePathCoord::max
(-$x_minimum, -$y_minimum, $x_maximum, $y_maximum);
}
return undef;
}
*_NumSeq_Coord_MaxAbs_integer = \&_NumSeq_Coord_Sum_integer;
#-------------
# AbsX
sub _NumSeq_Coord_AbsX_min {
my ($self) = @_;
# if positive min or negative max then 0 is not crossed and have an AbsX
# min which is bigger than 0
{ my $x_minimum = $self->x_minimum;
if (defined $x_minimum && $x_minimum > 0) { return $x_minimum; }
}
{ my $x_maximum = $self->x_maximum;
if (defined $x_maximum && $x_maximum < 0) { return - $x_maximum; }
}
return 0;
}
sub _NumSeq_Coord_AbsX_max {
my ($self) = @_;
# if bounded above and below then have an AbsX
if (defined (my $x_minimum = $self->x_minimum)) {
if (defined (my $x_maximum = $self->x_maximum)) {
return Math::NumSeq::PlanePathCoord::max
(abs($x_minimum), abs($x_maximum));
}
}
return undef;
}
#-------------
# AbsY
sub _NumSeq_Coord_AbsY_min {
my ($self) = @_;
# if positive min or negative max then 0 is not crossed and have an AbsY
# min which is bigger than 0
{ my $y_minimum = $self->y_minimum;
if (defined $y_minimum && $y_minimum > 0) { return $y_minimum; }
}
{ my $y_maximum = $self->y_maximum;
if (defined $y_maximum && $y_maximum < 0) { return - $y_maximum; }
}
return 0;
}
sub _NumSeq_Coord_AbsY_max {
my ($self) = @_;
# if bounded above and below then have an AbsY
if (defined (my $y_minimum = $self->y_minimum)) {
if (defined (my $y_maximum = $self->y_maximum)) {
return Math::NumSeq::PlanePathCoord::max
(abs($y_minimum), abs($y_maximum));
}
}
return undef;
}
#-------------
sub _NumSeq_Coord_pred_X {
my ($path, $value) = @_;
return (($path->figure ne 'square' || $value == int($value))
&& ($path->x_negative || $value >= 0));
}
sub _NumSeq_Coord_pred_Y {
my ($path, $value) = @_;
return (($path->figure ne 'square' || $value == int($value))
&& ($path->y_negative || $value >= 0));
}
sub _NumSeq_Coord_pred_Sum {
my ($path, $value) = @_;
return (($path->figure ne 'square' || $value == int($value))
&& ($path->x_negative || $path->y_negative || $value >= 0));
}
sub _NumSeq_Coord_pred_SumAbs {
my ($path, $value) = @_;
return (($path->figure ne 'square' || $value == int($value))
&& $value >= 0);
}
#--------------------------
sub _NumSeq_Coord_pred_Radius {
my ($path, $value) = @_;
return $path->_NumSeq_Coord_pred_RSquared($value*$value);
}
sub _NumSeq_Coord_pred_RSquared {
my ($path, $value) = @_;
# FIXME: this should be whether x^2+y^2 ever occurs, which is no prime
# factor 4k+3 or some such
return (($path->figure ne 'square' || $value == int($value))
&& $value >= 0);
}
#--------------------------
sub _NumSeq_Coord_pred_TRadius {
my ($path, $value) = @_;
return $path->_NumSeq_Coord_pred_RSquared($value*$value);
}
sub _NumSeq_Coord_pred_TRSquared {
my ($path, $value) = @_;
# FIXME: this should be whether x^2+3*y^2 occurs ...
return (($path->figure ne 'square' || $value == int($value))
&& $value >= 0);
}
#--------------------------
use constant _NumSeq_Coord_Depth_min => 0;
sub _NumSeq_Coord_Depth_max {
my ($path, $value) = @_;
return ($path->tree_n_num_children($path->n_start)
? undef # is a tree, default infinite max depth
: 0); # not a tree, depth always 0
}
use constant _NumSeq_Coord_Depth_integer => 1;
use constant _NumSeq_Coord_Depth_non_decreasing => 1; # usually
#--------------------------
use constant _NumSeq_Coord_NumChildren_integer => 1;
# compare with "==" to be numeric style, just in case some overloaded
# class stringizes to "1.0" or some such nonsense
sub _NumSeq_Coord_pred_NumChildren {
my ($self, $value) = @_;
foreach my $num ($self->tree_num_children_list) {
if ($value == $num) { return 1; }
}
return 0;
}
#--------------------------
use constant _NumSeq_Coord_NumSiblings_min => 0; # root node no siblings
sub _NumSeq_Coord_NumSiblings_max {
my ($path) = @_;
return List::Util::max(0,
# not including self
$path->tree_num_children_maximum - 1);
}
use constant _NumSeq_Coord_NumSiblings_integer => 1;
# if NumChildren=const except for NumChildren=0 then have NumSiblings=const-1
# so NumSiblings=0 at the root and thereafter non-decreasing
sub _NumSeq_Coord_NumSiblings_non_decreasing {
my ($path) = @_;
my @num_children = $path->tree_num_children_list;
if ($num_children[0] == 0) { shift @num_children; }
return (scalar(@num_children) <= 1);
}
#--------------------------
use constant _NumSeq_Coord_LeafDistance_integer => 1;
use constant _NumSeq_Coord_LeafDistance_min => 0;
use constant _NumSeq_Coord_LeafDistance_max => 0;
#--------------------------
sub _NumSeq_Coord_SubHeight_min {
my ($path) = @_;
if ($path->tree_any_leaf) {
return 0; # height 0 at a leaf
} else {
return undef; # actually +infinity
}
}
sub _NumSeq_Coord_SubHeight_max {
my ($path) = @_;
return ($path->tree_n_num_children($path->n_start)
? undef # is a tree, default infinite max height
: 0); # not a tree, height always 0
}
use constant _NumSeq_Coord_SubHeight_integer => 1;
#--------------------------
sub _NumSeq_Coord_RootN_min {
my ($path) = @_;
return $path->n_start;
}
sub _NumSeq_Coord_RootN_max {
my ($path) = @_;
return $path->n_start
+ List::Util::max(0, $path->tree_num_roots()-1);
}
use constant _NumSeq_Coord_RootN_integer => 1;
sub _NumSeq_Coord_IsLeaf_min {
my ($path) = @_;
# if num_children>0 occurs then that's a non-leaf node so IsLeaf=0 occurs
return ($path->tree_num_children_maximum() > 0 ? 0 : 1);
}
sub _NumSeq_Coord_IsLeaf_max {
my ($path) = @_;
return ($path->tree_any_leaf() ? 1 : 0);
}
# IsNonLeaf is opposite of IsLeaf
sub _NumSeq_Coord_IsNonLeaf_min {
my ($path) = @_;
return $path->_NumSeq_Coord_IsLeaf_max ? 0 : 1;
}
sub _NumSeq_Coord_IsNonLeaf_max {
my ($path) = @_;
return $path->_NumSeq_Coord_IsLeaf_min ? 0 : 1;
}
use constant _NumSeq_Coord_IsLeaf_integer => 1;
use constant _NumSeq_Coord_IsNonLeaf_integer => 1;
}
{ package Math::PlanePath::SquareSpiral;
sub _NumSeq_Coord_MaxAbs_non_decreasing {
my ($self) = @_;
return ($self->{'wider'} == 0);
}
use constant _NumSeq_Coord_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ X => 'A174344',
SumAbs => 'A214526', # "Manhattan" distance from n to 1
# OEIS-Catalogue: A174344 planepath=SquareSpiral coordinate_type=X
# OEIS-Catalogue: A214526 planepath=SquareSpiral coordinate_type=SumAbs
},
'wider=0,n_start=0' =>
{ Sum => 'A180714', # X+Y of square spiral
AbsDiff => 'A053615', # n..0..n, distance to pronic
# OEIS-Catalogue: A180714 planepath=SquareSpiral,n_start=0 coordinate_type=Sum
# OEIS-Other: A053615 planepath=SquareSpiral,n_start=0 coordinate_type=AbsDiff
},
};
}
{ package Math::PlanePath::GreekKeySpiral;
sub _NumSeq_Coord_MaxAbs_non_decreasing {
my ($self) = @_;
return ($self->{'turns'} == 0); # when same as SquareSpiral
}
}
{ package Math::PlanePath::PyramidSpiral;
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=0' =>
{ AbsX => 'A053615', # runs n..0..n, OFFSET=0
# OEIS-Catalogue: A053615 planepath=PyramidSpiral,n_start=0 coordinate_type=AbsX
},
};
}
{ package Math::PlanePath::TriangleSpiral;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
# { package Math::PlanePath::TriangleSpiralSkewed;
# }
{ package Math::PlanePath::DiamondSpiral;
use constant _NumSeq_Coord_SumAbs_non_decreasing => 1; # diagonals pos,neg
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=0' =>
{ X => 'A010751', # up 1, down 2, up 3, down 4, etc
AbsY => 'A053616',
# OEIS-Catalogue: A010751 planepath=DiamondSpiral,n_start=0
# OEIS-Other: A053616 planepath=DiamondSpiral,n_start=0 coordinate_type=AbsY
},
};
}
# { package Math::PlanePath::AztecDiamondRings;
# }
# { package Math::PlanePath::PentSpiralSkewed;
# }
{ package Math::PlanePath::HexSpiral;
# origin 0,0 if wider even, otherwise only X=1,Y=0 if wider odd
sub _NumSeq_Coord_TRSquared_min { $_[0]->rsquared_minimum }
# always odd/even according to wider odd/even
sub _NumSeq_Coord_Parity_min {
my ($self) = @_;
return $self->{'wider'} & 1;
}
*_NumSeq_Coord_Parity_max = \&_NumSeq_Coord_Parity_min;
# X!=Y when wider odd
*_NumSeq_Coord_HammingDist_min = \&_NumSeq_Coord_Parity_min;
*_NumSeq_Coord_MaxAbs_min = \&_NumSeq_Coord_Parity_min;
}
# { package Math::PlanePath::HexSpiralSkewed;
# }
{ package Math::PlanePath::HexArms;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
# { package Math::PlanePath::HeptSpiralSkewed;
# }
# { package Math::PlanePath::AnvilSpiral;
# }
# { package Math::PlanePath::OctagramSpiral;
# }
# { package Math::PlanePath::KnightSpiral;
# }
# { package Math::PlanePath::CretanLabyrinth;
# }
{ package Math::PlanePath::SquareArms;
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # successive squares
}
# { package Math::PlanePath::DiamondArms;
# }
{ package Math::PlanePath::SacksSpiral;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_Radius_increasing => 1; # Radius==sqrt($i)
use constant _NumSeq_Coord_RSquared_smaller => 0; # RSquared==$i
use constant _NumSeq_Coord_RSquared_integer => 1;
use constant _NumSeq_Coord_oeis_anum =>
{ '' =>
{ RSquared => 'A001477', # integers 0,1,2,3,etc
# OEIS-Other: A001477 planepath=SacksSpiral coordinate_type=RSquared
},
};
}
{ package Math::PlanePath::VogelFloret;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_AbsDiff_min_is_infimum => 1;
use constant _NumSeq_MinAbs_min_is_infimum => 1;
use constant _NumSeq_MaxAbs_min_is_infimum => 1;
sub _NumSeq_Coord_Radius_min {
my ($self) = @_;
# starting N=1 at R=radius_factor*sqrt(1), theta=something
return $self->{'radius_factor'};
}
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
# starting N=1 at R=radius_factor*sqrt(1), theta=something
my ($x,$y) = $self->n_to_xy($self->n_start);
return $x*$x + 3*$y*$y;
}
sub _NumSeq_Coord_Radius_func {
my ($seq, $i) = @_;
### VogelFloret Radius: $i, $seq->{'planepath_object'}
# R=radius_factor*sqrt($n)
# avoid sin/cos in the main n_to_xy()
my $path = $seq->{'planepath_object'};
my $rf = $path->{'radius_factor'};
# promote BigInt $i -> BigFloat so that sqrt() doesn't round, and in
# case radius_factor is not an integer
if (ref $i && $i->isa('Math::BigInt') && $rf != int($rf)) {
require Math::BigFloat;
$i = Math::BigFloat->new($i);
}
return sqrt($i) * $rf;
}
use constant _NumSeq_Coord_Radius_increasing => 1; # Radius==sqrt($i)
use constant _NumSeq_Coord_RSquared_smaller => 0; # RSquared==$i
}
{ package Math::PlanePath::TheodorusSpiral;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_Radius_increasing => 1; # Radius==sqrt($i)
use constant _NumSeq_Coord_RSquared_smaller => 0; # RSquared==$i
use constant _NumSeq_Coord_RSquared_integer => 1;
use constant _NumSeq_Coord_oeis_anum =>
{ '' =>
{ RSquared => 'A001477', # integers 0,1,2,3,etc
# OEIS-Other: A001477 planepath=TheodorusSpiral coordinate_type=RSquared
},
};
}
{ package Math::PlanePath::ArchimedeanChords;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_Radius_increasing => 1; # spiralling outwards
}
{ package Math::PlanePath::MultipleRings;
#---------
# X
sub _NumSeq_Coord_X_increasing {
my ($self) = @_;
# step==0 trivial on X axis
return ($self->{'step'} == 0 ? 1 : 0);
}
sub _NumSeq_Coord_X_integer {
my ($self) = @_;
return ($self->{'step'} == 0); # step==0 trivial on X axis
}
#---------
# Y
*_NumSeq_Coord_Y_integer = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Y_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Sum_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_DiffXY_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_DiffXYdiv2_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_TRSquared_integer = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Product_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Product_integer = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_BitAnd_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_BitOr_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_BitXor_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Min_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Max_increasing = \&_NumSeq_Coord_X_increasing;
#---------
# SumAbs
sub _NumSeq_Coord_SumAbs_non_decreasing {
my ($self) = @_;
# step==0 trivial on X axis
# polygon step=4 same x+y in ring, others vary
return ($self->{'step'} == 0
|| ($self->{'ring_shape'} eq 'polygon' && $self->{'step'} == 4)
? 1
: 0);
}
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_X_increasing;
#---------
# Product
sub _NumSeq_Coord_Product_max {
my ($self) = @_;
# step==0 trivial on X axis
# polygon step=4 same x+y in ring, others vary
return ($self->{'step'} == 0 ? 0 # step=0 always Y=0 so X*Y=0
: undef);
}
*_NumSeq_Coord_BitAnd_max = \&_NumSeq_Coord_Product_max;
#---------
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_X_increasing;
sub _NumSeq_AbsDiff_min_is_infimum {
my ($self) = @_;
# step multiple of 4 always falls on X=Y, otherwise approaches 0 only
return ($self->{'ring_shape'} eq 'polygon'
&& $self->{'step'} % 4);
}
#---------
# RSquared
sub _NumSeq_Coord_RSquared_smaller {
my ($self) = @_;
# step==0 on X axis RSquared is i^2, bigger than i.
# step=1 is 0,1,1,4,4,4,9,9,9,9,16,16,16,16,16 etc k+1 repeats of k^2,
# bigger than i from i=5 onwards
return ($self->{'step'} <= 1 ? 0 : 1);
}
*_NumSeq_Coord_RSquared_integer = \&_NumSeq_Coord_Radius_integer;
*_NumSeq_Coord_RSquared_non_decreasing = \&_NumSeq_Coord_Radius_non_decreasing;
#---------
# Radius
sub _NumSeq_Coord_Radius_integer {
my ($self) = @_;
# step==0 on X axis R=N
# step==1 start X=0,Y=0, spaced 1 apart on X axis, same radius for others
# step==6 start X=1,Y=0, spaced 1 apart
return ($self->{'step'} <= 1 || $self->{'step'} == 6);
}
sub _NumSeq_Coord_Radius_non_decreasing {
my ($self) = @_;
# circle is non-decreasing, polygon varies
return ! ($self->{'ring_shape'} eq 'polygon' && $self->{'step'} >= 3);
}
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_X_increasing;
#---------
# TRadius
sub _NumSeq_Coord_TRadius_min {
my ($self) = @_;
return $self->_NumSeq_Coord_Radius_min;
}
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
return $self->rsquared_minimum;
}
sub _NumSeq_Coord_TRadius_non_decreasing {
my ($self) = @_;
# step==0 trivial on X axis
return ($self->{'step'} == 0 ? 1 : 0);
}
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_TRadius_integer = \&_NumSeq_Coord_X_increasing;
#---------
# GCD
*_NumSeq_Coord_GCD_integer = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_GCD_increasing = \&_NumSeq_Coord_X_increasing;
#---------
# IntXY
# step=0 X/0 so IntXY=X
*_NumSeq_Coord_IntXY_increasing = \&_NumSeq_Coord_X_increasing;
#---------
# FracXY
sub _NumSeq_Coord_FracXY_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 : 1);
}
sub _NumSeq_FracXY_max_is_supremum {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 : 1);
}
*_NumSeq_Coord_FracXY_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_FracXY_integer = \&_NumSeq_Coord_X_increasing;
sub _NumSeq_Parity_min_is_infimum {
my ($self) = @_;
return $self->{'ring_shape'} eq 'polygon';
}
use constant _NumSeq_Coord_oeis_anum =>
{
# MultipleRings step=0 is trivial X=N,Y=0
'step=0,ring_shape=circle' =>
{ Y => 'A000004', # all-zeros
Product => 'A000004', # all-zeros
# OEIS-Other: A000004 planepath=MultipleRings,step=0 coordinate_type=Y
# OEIS-Other: A000004 planepath=MultipleRings,step=0 coordinate_type=Product
# OFFSET
# X => 'A001477', # integers 0 upwards
# Sum => 'A001477', # integers 0 upwards
# AbsDiff => 'A001477', # integers 0 upwards
# Radius => 'A001477', # integers 0 upwards
# DiffXY => 'A001477', # integers 0 upwards
# DiffYX => 'A001489', # negative integers 0 downwards
# RSquared => 'A000290', # squares 0 upwards
# # OEIS-Other: A001477 planepath=MultipleRings,step=0 coordinate_type=X
# # OEIS-Other: A001477 planepath=MultipleRings,step=0 coordinate_type=Sum
# # OEIS-Other: A001477 planepath=MultipleRings,step=0 coordinate_type=AbsDiff
# # OEIS-Other: A001477 planepath=MultipleRings,step=0 coordinate_type=Radius
# # OEIS-Other: A001477 planepath=MultipleRings,step=0 coordinate_type=DiffXY
# # OEIS-Other: A001489 planepath=MultipleRings,step=0 coordinate_type=DiffYX
# # OEIS-Other: A000290 planepath=MultipleRings,step=0 coordinate_type=RSquared
},
};
}
# { package Math::PlanePath::PixelRings;
# }
# { package Math::PlanePath::FilledRings;
# }
{ package Math::PlanePath::Hypot;
*_NumSeq_Coord_TRSquared_min = \&rsquared_minimum;
# in order of radius so monotonic, but always have 4x duplicates or more
use constant _NumSeq_Coord_Radius_non_decreasing => 1;
sub _NumSeq_Coord_HammingDist_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd' ? 1 : 0);
}
*_NumSeq_Coord_Parity_min = \&_NumSeq_Coord_HammingDist_min;
*_NumSeq_Coord_MaxAbs_min = \&_NumSeq_Coord_HammingDist_min;
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->{'points'} eq 'even' ? 0 : 1);
}
}
{ package Math::PlanePath::HypotOctant;
use constant _NumSeq_Coord_IntXY_min => 1; # triangular X>=Y so X/Y >= 1
*_NumSeq_Coord_TRSquared_min = \&rsquared_minimum;
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
# "odd" always has X!=Ymod2 so differ in low bit
return ($self->{'points'} eq 'odd' ? 1 : 0);
}
# in order of radius so monotonic, but can have duplicates
use constant _NumSeq_Coord_Radius_non_decreasing => 1;
sub _NumSeq_Coord_HammingDist_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd' ? 1 : 0);
}
sub _NumSeq_Coord_Parity_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd' ? 1 : 0);
}
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->{'points'} eq 'even' ? 0 : 1);
}
}
{ package Math::PlanePath::TriangularHypot;
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd'
? 1 # odd at X=1,Y=0
: $self->{'points'} eq 'hex_centred'
? 4 # hex_centred at X=2,Y=0 or X=1,Y=1
: 0); # even,all at X=0,Y=0
}
# in order of triangular radius so monotonic, but can have duplicates so
# non-decreasing
use constant _NumSeq_Coord_TRadius_non_decreasing => 1;
sub _NumSeq_Coord_HammingDist_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd' ? 1 : 0); # X!=Y when odd
}
*_NumSeq_Coord_Parity_min = \&_NumSeq_Coord_HammingDist_min;
sub _NumSeq_Coord_MaxAbs_min {
my ($self) = @_;
return ($self->{'points'} eq 'odd' || $self->{'points'} eq 'hex_centred'
? 1 : 0);
}
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->{'points'} eq 'odd' || $self->{'points'} eq 'all' ? 1 : 0);
}
}
{ package Math::PlanePath::PythagoreanTree;
use constant _NumSeq_Coord_SubHeight_min => undef;
use constant _NumSeq_Coord_LeafDistance_max => undef;
{
my %_NumSeq_Coord_IntXY_min = (AB => 0, # A>=1,B>=1 so int(A/B)>=0
AC => 0, # A 0, # B 1, # octant X>=Y+1 so X/Y>1
SM => 0, # A>=1,B>=1 so int(A/B)>=0
SC => 0,
MC => 0,
);
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_min{$self->{'coordinates'}};
}
}
{
my %_NumSeq_Coord_IntXY_max = (AC => 0, # A 0, # B 0, # X 0, # X 0, # X{'coordinates'}};
}
}
# P=2,Q=1 frac=0
# otherwise A,B,C have no common factor and >1 so frac!=0
sub _NumSeq_FracXY_min_is_infimum {
my ($self) = @_;
return $self->{'coordinates'} ne 'PQ';
}
{
my %_NumSeq_Coord_Denominator_min = (AB => 4, # at A=3,B=4 no common factor
AC => 5, # at A=3,B=5
BC => 5, # at B=4,B=5
PQ => 1, # at P=2,Q=1
);
sub _NumSeq_Coord_Denominator_min {
my ($self) = @_;
return $_NumSeq_Coord_Denominator_min{$self->{'coordinates'}};
}
}
{
my %_NumSeq_Coord_BitAnd_min = (AB => 0, # at X=3,Y=4
AC => 1, # at X=3,Y=5
BC => 0, # at X=8,Y=17
PQ => 0, # at X=2,Y=1
SM => 0, # at X=3,Y=4
SC => 0, # at X=3,Y=5
MC => 0, # at X=4,Y=5
);
sub _NumSeq_Coord_BitAnd_min {
my ($self) = @_;
return $_NumSeq_Coord_BitAnd_min{$self->{'coordinates'}};
}
}
{
my %_NumSeq_Coord_BitOr_min = (AB => 7, # at A=3,B=4
AC => 7, # at A=3,C=5
BC => 5, # at B=4,C=5
PQ => 3, # at P=2,Q=1
SM => 7, # at X=3,Y=4
SC => 7, # at X=3,Y=5
MC => 5, # at X=4,Y=5
);
sub _NumSeq_Coord_BitOr_min {
my ($self) = @_;
return $_NumSeq_Coord_BitOr_min{$self->{'coordinates'}};
}
}
{
my %_NumSeq_Coord_BitXor_min = (AB => 1, # at X=21,Y=20
AC => 6, # at X=3,Y=5
BC => 1, # at X=4,Y=5
PQ => 1, # at X=3,Y=2
SM => 1, # at X=3,Y=4
SC => 6, # at X=3,Y=5
MC => 1, # at X=4,Y=5
);
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
return $_NumSeq_Coord_BitXor_min{$self->{'coordinates'}};
}
}
sub _NumSeq_Coord_Radius_integer {
my ($self) = @_;
return ($self->{'coordinates'} eq 'AB' # hypot
|| $self->{'coordinates'} eq 'SM'); # hypot
}
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
{
my %_NumSeq_Coord_Parity_min = (PQ => 1, # one odd one even, so odd always
AB => 1, # odd,even so odd always
BA => 1,
BC => 1, # even,odd so odd always
);
sub _NumSeq_Coord_Parity_min {
my ($self) = @_;
return $_NumSeq_Coord_Parity_min{$self->{'coordinates'}} || 0;
}
}
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->{'coordinates'} eq 'AC'
? 0 # odd,odd so even always
: 1);
}
# Not quite right.
# sub _NumSeq_Coord_pred_Radius {
# my ($path, $value) = @_;
# return ($value >= 0
# && ($path->{'coordinate_type'} ne 'AB'
# || $value == int($value)));
# }
}
{ package Math::PlanePath::RationalsTree;
use constant _NumSeq_Coord_BitAnd_min => 0; # X=1,Y=2
use constant _NumSeq_Coord_BitXor_min => 0; # X=1,Y=1
use constant _NumSeq_Coord_SubHeight_min => undef;
use constant _NumSeq_Coord_LeafDistance_max => undef;
use constant _NumSeq_Coord_oeis_anum =>
{ 'tree_type=SB' =>
{ IntXY => 'A153036',
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Catalogue: A153036 planepath=RationalsTree coordinate_type=IntXY
# OEIS-Catalogue: A000523 planepath=RationalsTree coordinate_type=Depth
# Not quite, OFFSET n=0 cf N=1 here
# Y => 'A047679', # SB denominator
# # OEIS-Catalogue: A047679 planepath=RationalsTree coordinate_type=Y
#
# X => 'A007305', # SB numerators but starting extra 0,1
# Sum => 'A007306', # Farey/SB denominators, but starting extra 1,1
# Product => 'A119272', # num*den, but starting extra 1,1
# cf A054424 permutation
},
'tree_type=CW' =>
{
# A070871 Stern adjacent S(n)*S(n+1), or Conway's alimentary function,
# cf A070872 where S(n)*S(n+1) = n
# A070873 where S(n)*S(n+1) > n
# A070874 where S(n)*S(n+1) < n
Product => 'A070871',
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Catalogue: A070871 planepath=RationalsTree,tree_type=CW coordinate_type=Product
# OEIS-Other: A000523 planepath=RationalsTree,tree_type=CW coordinate_type=Depth
# Not quite, A007814 has extra initial 0, OFFSET=0 "0,1,0,2,0"
# whereas path CW IntXY starts N=1 "1,0,2,0,1"
# IntXY => 'A007814', # countlow1bits(N)
# # OEIS-Other: A007814 planepath=RationalsTree,tree_type=CW coordinate_type=IntXY
# Not quite, CW X and Y is Stern diatomic A002487, but RationalsTree
# starts N=0 X=1,1,2 or Y=1,2 rather than from 0
# Not quite, CW DiffYX is A070990 stern diatomic first diffs, but
# path starts N=1 diff="0,1,-1,2,-1,1,-2", whereas A070990 starts n=0
# "1,-1,2,-1,1,-2" one less term and would be n_start=-1
},
'tree_type=AYT' =>
{ X => 'A020650', # AYT numerator
Y => 'A020651', # AYT denominator
Sum => 'A086592', # Kepler's tree denominators
SumAbs => 'A086592', # Kepler's tree denominators
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
IntXY => 'A135523',
# OEIS-Catalogue: A020650 planepath=RationalsTree,tree_type=AYT coordinate_type=X
# OEIS-Catalogue: A020651 planepath=RationalsTree,tree_type=AYT coordinate_type=Y
# OEIS-Other: A086592 planepath=RationalsTree,tree_type=AYT coordinate_type=Sum
# OEIS-Other: A000523 planepath=RationalsTree,tree_type=AYT coordinate_type=Depth
# OEIS-Catalogue: A135523 planepath=RationalsTree,tree_type=AYT coordinate_type=IntXY
# Not quite, DiffYX almost A070990 Stern diatomic first differences,
# but we have an extra 0 at the start, and we start i=1 rather than
# n=0 too
},
'tree_type=HCS' =>
{
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Other: A000523 planepath=RationalsTree,tree_type=HCS coordinate_type=Depth
# # Not quite, OFFSET=0 value=1/1 corresponding to N=0 X=0/Y=1 here
# Sum => 'A071585', # rats>=1 is HCS num+den
# Y => 'A071766', # rats>=1 HCS denominator
# # OEIS-Catalogue: A071585 planepath=RationalsTree,tree_type=HCS coordinate_type=X
# # OEIS-Catalogue: A071766 planepath=RationalsTree,tree_type=HCS coordinate_type=Y
},
'tree_type=Bird' =>
{ X => 'A162909', # Bird tree numerators
Y => 'A162910', # Bird tree denominators
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Catalogue: A162909 planepath=RationalsTree,tree_type=Bird coordinate_type=X
# OEIS-Catalogue: A162910 planepath=RationalsTree,tree_type=Bird coordinate_type=Y
# OEIS-Other: A000523 planepath=RationalsTree,tree_type=Bird coordinate_type=Depth
},
'tree_type=Drib' =>
{ X => 'A162911', # Drib tree numerators
Y => 'A162912', # Drib tree denominators
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Catalogue: A162911 planepath=RationalsTree,tree_type=Drib coordinate_type=X
# OEIS-Catalogue: A162912 planepath=RationalsTree,tree_type=Drib coordinate_type=Y
# OEIS-Other: A000523 planepath=RationalsTree,tree_type=Drib coordinate_type=Depth
},
'tree_type=L' =>
{
X => 'A174981', # numerator
# OEIS-Catalogue: A174981 planepath=RationalsTree,tree_type=L coordinate_type=X
# # Not quite, A002487 extra initial, so n=2 is denominator at N=0
# Y => 'A002487', # denominator, stern diatomic
# # OEIS-Catalogue: A071585 planepath=RationalsTree,tree_type=HCS coordinate_type=Y
# Not quite, A000523 is OFFSET=1 path starts N=0
# Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
},
};
}
{ package Math::PlanePath::FractionsTree;
use constant _NumSeq_Coord_IntXY_max => 0; # X/Y<1 always
use constant _NumSeq_Coord_IntXY_non_decreasing => 1;
use constant _NumSeq_FracXY_min_is_infimum => 1; # no common factor
use constant _NumSeq_Coord_BitXor_min => 1; # X=2,Y=3
use constant _NumSeq_Coord_SubHeight_min => undef;
use constant _NumSeq_Coord_LeafDistance_max => undef;
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
use constant _NumSeq_Coord_oeis_anum =>
{ 'tree_type=Kepler' =>
{ X => 'A020651', # numerators, same as AYT denominators
Y => 'A086592', # Kepler half-tree denominators
DiffYX => 'A020650', # AYT numerators
AbsDiff => 'A020650', # AYT numerators
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Other: A020651 planepath=FractionsTree coordinate_type=X
# OEIS-Catalogue: A086592 planepath=FractionsTree coordinate_type=Y
# OEIS-Other: A020650 planepath=FractionsTree coordinate_type=DiffYX
# OEIS-Other: A020650 planepath=FractionsTree coordinate_type=AbsDiff
# OEIS-Other: A000523 planepath=FractionsTree coordinate_type=Depth
# Not quite, Sum is from 1/2 value=3 skipping the initial value=2 in
# A086593 which would be 1/1. Also is every second denominator, but
# again no initial value=2.
# Sum => 'A086593',
# Y_odd => 'A086593', # at N=1,3,5,etc
},
};
}
{ package Math::PlanePath::CfracDigits;
use constant _NumSeq_Coord_IntXY_max => 0; # upper octant 0 < X/Y < 1
use constant _NumSeq_Coord_IntXY_non_decreasing => 1;
use constant _NumSeq_FracXY_min_is_infimum => 1; # X,Y no common factor
# X=Y doesn't occur so X,Y always differ by at least 1 bit. The smallest
# two differing by 1 bit are X=1,Y=2.
use constant _NumSeq_Coord_BitOr_min => 3; # X=1,Y=2
use constant _NumSeq_Coord_BitXor_min => 1; # X=2,Y=3
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
# use constant _NumSeq_Coord_oeis_anum =>
# { 'radix=2' =>
# {
# },
# };
}
{ package Math::PlanePath::ChanTree;
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
# except in k=2 Calkin-Wilf, point X=1,Y=1 doesn't occur, only X=1,Y=2
# or X=2,Y=1
return ($self->{'k'} == 2 ? 1 : 2);
}
*_NumSeq_Coord_MaxAbs_min = \&_NumSeq_Coord_Max_min;
use constant _NumSeq_Coord_SubHeight_min => undef;
use constant _NumSeq_Coord_LeafDistance_max => undef;
sub _NumSeq_Coord_Product_min {
my ($self) = @_;
return ($self->{'reduced'} || $self->{'k'} == 2
? 1 # X=1,Y=1 reduced or k=2 X=1,Y=1
: 2); # X=1,Y=2
}
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
return ($self->{'k'} == 2
|| ($self->{'reduced'} && ($self->{'k'} & 1) == 0)
? 4 # X=1,Y=1 reduced k even, or k=2 top 1/1
: 7); # X=2,Y=1
}
use constant _NumSeq_Coord_BitAnd_min => 0; # X=1,Y=2
sub _NumSeq_Coord_BitOr_min {
my ($self) = @_;
return ($self->{'k'} == 2 || $self->{'reduced'} ? 1 # X=1,Y=1
: $self->{'k'} & 1 ? 3 # k odd X=1,Y=2
: 2); # k even X=2,Y=2
}
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
return ($self->{'k'} == 2 || $self->{'reduced'} ? 0 # X=1,Y=1
: $self->{'k'} & 1 ? 1 # k odd X=2,Y=3
: 0); # k even X=2,Y=2
}
sub _NumSeq_Coord_Parity_min {
my ($self) = @_;
return ($self->{'k'} % 2
? 1 # k odd has one odd, one even, so odd
: 0);
}
# X!=Y when k odd
*_NumSeq_Coord_HammingDist_min = \&_NumSeq_Coord_Parity_min;
use constant _NumSeq_Coord_oeis_anum =>
{
do { # k=2 same as CW
my $cw = { Product => 'A070871',
Depth => 'A000523', # floor(log2(n)) starting OFFSET=1
# OEIS-Other: A070871 planepath=ChanTree,k=2,n_start=1 coordinate_type=Product
# OEIS-Other: A000523 planepath=ChanTree,k=2,n_start=1 coordinate_type=Depth
};
(
'k=2,n_start=1' => $cw,
# 'k=2,reduced=0,points=even,n_start=1' => $cw,
# 'k=2,reduced=1,points=even,n_start=1' => $cw,
# 'k=2,reduced=0,points=all,n_start=1' => $cw,
# 'k=2,reduced=1,points=all,n_start=1' => $cw,
),
},
# 'k=3,reduced=0,points=even,n_start=0' =>
'k=3,n_start=0' =>
{ X => 'A191379',
# OEIS-Catalogue: A191379 planepath=ChanTree
},
};
}
{ package Math::PlanePath::PeanoCurve;
use constant _NumSeq_Coord_oeis_anum =>
{
# Same in GrayCode and WunderlichSerpentine
'radix=3' =>
{ X => 'A163528',
Y => 'A163529',
Sum => 'A163530',
SumAbs => 'A163530',
RSquared => 'A163531',
# OEIS-Catalogue: A163528 planepath=PeanoCurve coordinate_type=X
# OEIS-Catalogue: A163529 planepath=PeanoCurve coordinate_type=Y
# OEIS-Catalogue: A163530 planepath=PeanoCurve coordinate_type=Sum
# OEIS-Other: A163530 planepath=PeanoCurve coordinate_type=SumAbs
# OEIS-Catalogue: A163531 planepath=PeanoCurve coordinate_type=RSquared
},
};
}
{ package Math::PlanePath::WunderlichSerpentine;
use constant _NumSeq_Coord_oeis_anum =>
{
do {
my $peano = { X => 'A163528',
Y => 'A163529',
Sum => 'A163530',
SumAbs => 'A163530',
RSquared => 'A163531',
};
# OEIS-Other: A163528 planepath=WunderlichSerpentine,serpentine_type=Peano,radix=3 coordinate_type=X
# OEIS-Other: A163529 planepath=WunderlichSerpentine,serpentine_type=Peano,radix=3 coordinate_type=Y
# OEIS-Other: A163530 planepath=WunderlichSerpentine,serpentine_type=Peano,radix=3 coordinate_type=Sum
# OEIS-Other: A163530 planepath=WunderlichSerpentine,serpentine_type=Peano,radix=3 coordinate_type=SumAbs
# OEIS-Other: A163531 planepath=WunderlichSerpentine,serpentine_type=Peano,radix=3 coordinate_type=RSquared
# ENHANCE-ME: with serpentine_type by bits too
('serpentine_type=Peano,radix=3' => $peano,
)
},
};
}
{ package Math::PlanePath::HilbertCurve;
use constant _NumSeq_Coord_oeis_anum =>
{ '' =>
{ X => 'A059253',
Y => 'A059252',
Sum => 'A059261',
SumAbs => 'A059261',
DiffXY => 'A059285',
RSquared => 'A163547',
HammingDist => 'A139351', # count 1-bits at even bit positions
# OEIS-Catalogue: A059253 planepath=HilbertCurve coordinate_type=X
# OEIS-Catalogue: A059252 planepath=HilbertCurve coordinate_type=Y
# OEIS-Catalogue: A059261 planepath=HilbertCurve coordinate_type=Sum
# OEIS-Other: A059261 planepath=HilbertCurve coordinate_type=SumAbs
# OEIS-Catalogue: A059285 planepath=HilbertCurve coordinate_type=DiffXY
# OEIS-Catalogue: A163547 planepath=HilbertCurve coordinate_type=RSquared
# OEIS-Other: A139351 planepath=HilbertCurve coordinate_type=HammingDist
},
};
}
{ package Math::PlanePath::HilbertSpiral;
use constant _NumSeq_Coord_oeis_anum =>
{ '' =>
{
# HilbertSpiral going negative is mirror on X=-Y line, which is
# (-Y,-X), so DiffXY = -Y-(-X) = X-Y same diff as plain HilbertCurve.
DiffXY => 'A059285',
# OEIS-Other: A059285 planepath=HilbertSpiral coordinate_type=DiffXY
},
};
}
{ package Math::PlanePath::ZOrderCurve;
use constant _NumSeq_Coord_oeis_anum =>
{ 'radix=2' =>
{ X => 'A059905', # alternate bits first
Y => 'A059906', # alternate bits second
# OEIS-Catalogue: A059905 planepath=ZOrderCurve coordinate_type=X
# OEIS-Catalogue: A059906 planepath=ZOrderCurve coordinate_type=Y
},
'radix=3' =>
{ X => 'A163325', # alternate ternary digits first
Y => 'A163326', # alternate ternary digits second
# OEIS-Catalogue: A163325 planepath=ZOrderCurve,radix=3 coordinate_type=X
# OEIS-Catalogue: A163326 planepath=ZOrderCurve,radix=3 coordinate_type=Y
},
'radix=10,i_start=1' =>
{
# i_start=1 per A080463 offset=1, it skips initial zero
Sum => 'A080463',
SumAbs => 'A080463',
# OEIS-Catalogue: A080463 planepath=ZOrderCurve,radix=10 coordinate_type=Sum i_start=1
# OEIS-Other: A080463 planepath=ZOrderCurve,radix=10 coordinate_type=SumAbs i_start=1
},
'radix=10,i_start=10' =>
{
# i_start=10 per A080464 OFFSET=10, it skips all but one initial zeros
Product => 'A080464',
# OEIS-Catalogue: A080464 planepath=ZOrderCurve,radix=10 coordinate_type=Product i_start=10
AbsDiff => 'A080465',
# OEIS-Catalogue: A080465 planepath=ZOrderCurve,radix=10 coordinate_type=AbsDiff i_start=10
},
};
}
{ package Math::PlanePath::GrayCode;
use constant _NumSeq_Coord_oeis_anum =>
{
do {
my $peano = { X => 'A163528',
Y => 'A163529',
Sum => 'A163530',
SumAbs => 'A163530',
RSquared => 'A163531',
};
('apply_type=TsF,gray_type=reflected,radix=3' => $peano,
'apply_type=FsT,gray_type=reflected,radix=3' => $peano,
),
# OEIS-Other: A163528 planepath=GrayCode,apply_type=TsF,radix=3 coordinate_type=X
# OEIS-Other: A163529 planepath=GrayCode,apply_type=TsF,radix=3 coordinate_type=Y
# OEIS-Other: A163530 planepath=GrayCode,apply_type=TsF,radix=3 coordinate_type=Sum
# OEIS-Other: A163530 planepath=GrayCode,apply_type=TsF,radix=3 coordinate_type=SumAbs
# OEIS-Other: A163531 planepath=GrayCode,apply_type=TsF,radix=3 coordinate_type=RSquared
# OEIS-Other: A163528 planepath=GrayCode,apply_type=FsT,radix=3 coordinate_type=X
# OEIS-Other: A163529 planepath=GrayCode,apply_type=FsT,radix=3 coordinate_type=Y
# OEIS-Other: A163530 planepath=GrayCode,apply_type=FsT,radix=3 coordinate_type=Sum
# OEIS-Other: A163530 planepath=GrayCode,apply_type=FsT,radix=3 coordinate_type=SumAbs
# OEIS-Other: A163531 planepath=GrayCode,apply_type=FsT,radix=3 coordinate_type=RSquared
},
};
}
# { package Math::PlanePath::ImaginaryBase;
# }
# { package Math::PlanePath::ImaginaryHalf;
# }
{ package Math::PlanePath::CubicBase;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::Flowsnake;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::FlowsnakeCentres;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::GosperIslands;
use constant _NumSeq_Coord_TRSquared_min => 4; # minimum X=1,Y=1
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::GosperReplicate;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::GosperSide;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::KochCurve;
use constant _NumSeq_Coord_IntXY_min => 3; # at X=3,Y=1 among the Y>0 points
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::KochPeaks;
use constant _NumSeq_Coord_MaxAbs_min => 1; # odd always
use constant _NumSeq_Coord_TRSquared_min => 1; # minimum X=1,Y=0
use constant _NumSeq_Coord_Parity_min => 1; # odd always
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
}
{ package Math::PlanePath::KochSnowflakes;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_BitAnd_integer => 1; # only Y non-integer
use constant _NumSeq_Coord_TRSquared_min => 3*4/9; # minimum X=0,Y=2/3
use constant _NumSeq_Coord_MaxAbs_min => 2/3; # at N=3
use constant _NumSeq_Coord_TRadius_min => sqrt(_NumSeq_Coord_TRSquared_min);
use constant _NumSeq_Coord_GCD_integer => 0;
}
{ package Math::PlanePath::KochSquareflakes;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_MaxAbs_min => 1/2; # at N=1
use constant _NumSeq_Coord_Sum_integer => 1;
use constant _NumSeq_Coord_SumAbs_integer => 1;
use constant _NumSeq_Coord_DiffXY_integer => 1;
use constant _NumSeq_Coord_DiffYX_integer => 1;
use constant _NumSeq_Coord_AbsDiff_integer => 1;
use constant _NumSeq_Coord_BitXor_integer => 1; # 0.5 xor 0.5 cancels out
use constant _NumSeq_Coord_TRSquared_min => 1; # X=0.5,Y=0.5
use constant _NumSeq_Coord_TRSquared_integer => 1;
use constant _NumSeq_Coord_GCD_integer => 0; # GCD(1/2,1/2)=1/2
}
{ package Math::PlanePath::QuadricCurve;
use constant _NumSeq_Coord_IntXY_min => undef; # negatives
}
{ package Math::PlanePath::QuadricIslands;
use constant _NumSeq_Coord_X_integer => 0;
use constant _NumSeq_Coord_Y_integer => 0;
use constant _NumSeq_Coord_Sum_integer => 1; # 0.5 + 0.5 = integer
use constant _NumSeq_Coord_SumAbs_integer => 1;
use constant _NumSeq_Coord_DiffXY_integer => 1;
use constant _NumSeq_Coord_DiffYX_integer => 1;
use constant _NumSeq_Coord_AbsDiff_integer => 1;
use constant _NumSeq_Coord_GCD_integer => 0; # GCD(1/2,1/2)=1/2
# BitXor X=1/2=0.1 Y=-1/2=-0.1=...1111.0 BitXor=0
use constant _NumSeq_Coord_BitXor_integer => 1;
# TRSquared on X=1/2,Y=1/2 is TR^2 = (1/2)^2+3*(1/2)^2 = 1
use constant _NumSeq_Coord_TRSquared_integer => 1;
use constant _NumSeq_Coord_TRSquared_min => 1; # X=1/2,Y=1/2
}
{ package Math::PlanePath::SierpinskiTriangle;
sub _NumSeq_Coord_Y_non_decreasing {
my ($self) = @_;
return ($self->{'align'} ne 'diagonal'); # rows upwards, except diagonal
}
# Max==Y for align!=diagonal
*_NumSeq_Coord_Max_non_decreasing = \&_NumSeq_Coord_Y_non_decreasing;
*_NumSeq_Coord_MaxAbs_non_decreasing = \&_NumSeq_Coord_Y_non_decreasing;
sub _NumSeq_Coord_Sum_non_decreasing {
my ($self) = @_;
return ($self->{'align'} eq 'diagonal'); # anti-diagonals
}
*_NumSeq_Coord_SumAbs_non_decreasing = \&_NumSeq_Coord_Sum_non_decreasing;
use constant _NumSeq_Coord_IntXY_min => -1; # wedge
# align=diagonal has X,Y no 1-bits in common, so BitAnd==0
sub _NumSeq_Coord_BitAnd_max {
my ($self) = @_;
return ($self->{'align'} eq 'diagonal' ? 0
: undef);
}
sub _NumSeq_Coord_BitAnd_non_decreasing {
my ($self) = @_;
return ($self->{'align'} eq 'diagonal');
}
# align=right,diagonal has X,Y BitOr 1-bits accumulating ...
sub _NumSeq_Coord_BitOr_non_decreasing {
my ($self) = @_;
return ($self->{'align'} eq 'right'
|| $self->{'align'} eq 'diagonal');
}
# align=diagonal has X,Y no bits in common so is same as BitOr 1-bits
# accumulating ...
sub _NumSeq_Coord_BitXor_non_decreasing {
my ($self) = @_;
return ($self->{'align'} eq 'diagonal');
}
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return ($self->{'align'} eq 'triangular'
? 0 # triangular always even points
: 1);
}
use constant _NumSeq_Coord_LeafDistance_max => 4;
}
{ package Math::PlanePath::SierpinskiArrowhead;
use constant _NumSeq_Coord_IntXY_min => -1; # wedge
*_NumSeq_Coord_Parity_max
= \&Math::PlanePath::SierpinskiTriangle::_NumSeq_Coord_Parity_max;
}
{ package Math::PlanePath::SierpinskiArrowheadCentres;
use constant _NumSeq_Coord_IntXY_min => -1; # wedge
*_NumSeq_Coord_BitAnd_max
= \&Math::PlanePath::SierpinskiTriangle::_NumSeq_Coord_BitAnd_max;
*_NumSeq_Coord_BitAnd_non_decreasing
= \&Math::PlanePath::SierpinskiTriangle::_NumSeq_Coord_BitAnd_non_decreasing;
*_NumSeq_Coord_Parity_max
= \&Math::PlanePath::SierpinskiTriangle::_NumSeq_Coord_Parity_max;
}
{ package Math::PlanePath::SierpinskiCurve;
{
my @Max_min = (undef,
1, # 1 arm, octant X>Y and X>=1
1, # 2 arms, quadrant X>=1 or Y>=1
1, # 3 arms
0, # 4 arms
# more than 3 arm, Max goes negative unbounded
);
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
return $Max_min[$self->arms_count];
}
}
{
my @IntXY_min = (undef,
1, # octant X>Y so X/Y>1
0, # quadrant X>=0 so X/Y>=0
-1, # 3-oct X>=-Y so X/Y>=-1
); # arms>=4 has X unbounded negative
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $IntXY_min[$self->arms_count];
}
}
use constant _NumSeq_Coord_TRSquared_min => 1; # minimum X=1,Y=0
sub _NumSeq_Coord_BitOr_min {
my ($self) = @_;
return ($self->arms_count <= 2
? 1 # X=0,Y=0 not visited BitOr(X,Y)>=1
: undef); # going X negative
}
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
return ($self->arms_count <= 2
? 1 # X!=Y so BitXor(X,Y)>=1
: undef); # going X negative
}
}
{ package Math::PlanePath::SierpinskiCurveStair;
use constant _NumSeq_Coord_Max_min => 1;
*_NumSeq_Coord_IntXY_min = \&Math::PlanePath::SierpinskiCurve::_NumSeq_Coord_IntXY_min;
*_NumSeq_Coord_BitOr_min = \&Math::PlanePath::SierpinskiCurve::_NumSeq_Coord_BitOr_min;
*_NumSeq_Coord_BitXor_min = \&Math::PlanePath::SierpinskiCurve::_NumSeq_Coord_BitXor_min;
use constant _NumSeq_Coord_TRSquared_min => 1; # minimum X=1,Y=0
}
# { package Math::PlanePath::HIndexing;
# # except 0/0=inf
# # use constant _NumSeq_Coord_IntXY_max => 1; # upper octant X<=Y so X/Y<=1
# }
{ package Math::PlanePath::DragonCurve;
use constant _NumSeq_Coord_NumSurround4_min => 2;
# use constant _NumSeq_Coord_NumSurround6_min => 0; # ???
use constant _NumSeq_Coord_NumSurround8_min => 3;
}
{ package Math::PlanePath::DragonRounded;
use constant _NumSeq_Coord_TRSquared_min => 1; # minimum X=1,Y=0
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
use constant _NumSeq_Coord_MaxAbs_min => 1; # X!=Y
}
# { package Math::PlanePath::DragonMidpoint;
# }
{ package Math::PlanePath::AlternatePaper;
{
my @_NumSeq_Coord_IntXY_min = (undef,
1, # 1 arm, octant X+Y>=0
0, # 2 arms, X>=0
0, # 3 arms, X>-Y so X/Y>-1
); # more than 3 arm, X neg axis so undef
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_min[$self->arms_count];
}
} use constant _NumSeq_Coord_oeis_anum =>
{ 'i_start=1' =>
{ DiffXY => 'A020990', # GRS*(-1)^n cumulative
AbsDiff => 'A020990',
# Not quite, OFFSET=0 value=1 which corresponds to N=1 Sum=1, so
# A020986 doesn't have N=0 Sum=0.
# Sum => 'A020986', # GRS cumulative
# # OEIS-Catalogue: A020986 planepath=AlternatePaper coordinate_type=Sum i_start=1
# X_undoubled => 'A020986', # GRS cumulative
# Y_undoubled => 'A020990', # GRS*(-1)^n cumulative
},
};
}
{ package Math::PlanePath::AlternatePaperMidpoint;
{
my @_NumSeq_Coord_IntXY_min = (undef,
1, # 1 arm, octant X+Y>=0
0, # 2 arms, X>=0
0, # 3 arms, X>-Y so X/Y>-1
); # more than 3 arm, X neg axis so undef
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_min[$self->arms_count];
}
}
}
{ package Math::PlanePath::TerdragonCurve;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::TerdragonRounded;
use constant _NumSeq_Coord_TRSquared_min => 4; # either X=2,Y=0 or X=1,Y=1
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::TerdragonMidpoint;
use constant _NumSeq_Coord_TRSquared_min => 4; # either X=2,Y=0 or X=1,Y=1
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
# { package Math::PlanePath::R5DragonCurve;
# }
# { package Math::PlanePath::R5DragonMidpoint;
# }
# { package Math::PlanePath::CCurve;
# }
# { package Math::PlanePath::ComplexPlus;
# }
# { package Math::PlanePath::ComplexMinus;
# }
# { package Math::PlanePath::ComplexRevolving;
# }
{ package Math::PlanePath::Rows;
use constant _NumSeq_extra_parameter_info_list =>
{ name => 'width',
type => 'integer',
};
*_NumSeq_Coord_X_non_decreasing = \&_NumSeq_Coord_Y_increasing;
sub _NumSeq_Coord_Y_increasing {
my ($self) = @_;
return ($self->{'width'} == 1
? 1 # X=N,Y=0 only
: 0);
}
*_NumSeq_Coord_Min_max = \&x_maximum;
*_NumSeq_Coord_Max_increasing=\&_NumSeq_Coord_Y_increasing; # height=1 Max=Y
sub _NumSeq_Coord_Max_non_decreasing {
my ($self) = @_;
return ($self->{'width'} <= 2);
}
sub _NumSeq_Coord_Sum_non_decreasing {
my ($self) = @_;
return ($self->{'width'} <= 2
? 1 # width=1 is X=0,Y=N only, or width=2 is X=0,1,Y=N/2
: 0);
}
*_NumSeq_Coord_Sum_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_SumAbs_non_decreasing = \&_NumSeq_Coord_Sum_non_decreasing;
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_DiffYX_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_Product_non_decreasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_Y_increasing;
sub _NumSeq_Coord_BitAnd_max {
my ($self) = @_;
return $self->{'width'}-1; # at X=Y=width-1
}
*_NumSeq_Coord_BitAnd_non_decreasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_BitOr_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_BitXor_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_Radius_non_decreasing = \&_NumSeq_Coord_Sum_non_decreasing;
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_Radius_integer = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_GCD_increasing = \&_NumSeq_Coord_Y_increasing;
# width <= 2 one or two columns is increasing
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_Sum_non_decreasing;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=1,width=1' =>
{ Product => 'A000004', # all zeros
# OEIS-Other: A000004 planepath=Rows,width=1 coordinate_type=Product
# OFFSET
# Y => 'A001477', # integers 0 upwards
# Sum => 'A001477', # integers 0 upwards
# # OEIS-Other: A001477 planepath=Rows,width=1 coordinate_type=Y
# DiffXY => 'A001489', # negative integers 0 downwards
# DiffYX => 'A001477', # integers 0 upwards
# AbsDiff => 'A001477', # integers 0 upwards
# Radius => 'A001477', # integers 0 upwards
# RSquared => 'A000290', # squares 0 upwards
# # OEIS-Other: A001477 planepath=Rows,width=1 coordinate_type=Sum
# # OEIS-Other: A001489 planepath=Rows,width=1 coordinate_type=DiffXY
# # OEIS-Other: A001477 planepath=Rows,width=1 coordinate_type=DiffYX
# # OEIS-Other: A001477 planepath=Rows,width=1 coordinate_type=AbsDiff
# # OEIS-Other: A001477 planepath=Rows,width=1 coordinate_type=Radius
# # OEIS-Other: A000290 planepath=Rows,width=1 coordinate_type=RSquared
},
'n_start=0,width=2' =>
{ X => 'A000035', # 0,1 repeating OFFSET=0
Y => 'A004526', # 0,0,1,1,2,2,etc cf Math::NumSeq::Runs
# OEIS-Other: A000035 planepath=Rows,width=2,n_start=0 coordinate_type=X
# OEIS-Other: A004526 planepath=Rows,width=2,n_start=0 coordinate_type=Y
# # Not quite, A142150 OFFSET=0 starting 0,0,1,0,2 interleave integers
# # and 0 but Product here extra 0 start 0,0,0,1,0,2,0
# # Product => 'A142150'
#
# # Not quite, GCD=>'A057979' but A057979 extra initial 1
},
};
}
{ package Math::PlanePath::Columns;
use constant _NumSeq_extra_parameter_info_list =>
{ name => 'height',
type => 'integer',
};
sub _NumSeq_Coord_X_increasing {
my ($self) = @_;
return ($self->{'height'} == 1
? 1 # X=N,Y=0 only
: 0);
}
use constant _NumSeq_Coord_X_non_decreasing => 1; # columns across
*_NumSeq_Coord_Y_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Min_max = \&y_maximum;
*_NumSeq_Coord_Max_increasing=\&_NumSeq_Coord_X_increasing; # height=1 Max=X
sub _NumSeq_Coord_Max_non_decreasing {
my ($self) = @_;
return ($self->{'height'} <= 2);
}
*_NumSeq_Coord_Sum_increasing = \&_NumSeq_Coord_X_increasing;
sub _NumSeq_Coord_Sum_non_decreasing {
my ($self) = @_;
return ($self->{'height'} <= 2
? 1 # height=1 is X=N,Y=0 only, or height=2 is X=N/2,Y=0,1
: 0);
}
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_SumAbs_non_decreasing = \&_NumSeq_Coord_Sum_non_decreasing;
*_NumSeq_Coord_DiffXY_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Radius_integer = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_TRadius_integer = \&_NumSeq_Coord_X_increasing;
sub _NumSeq_Coord_BitAnd_max {
my ($self) = @_;
return $self->{'height'}-1; # at X=Y=height-1
}
*_NumSeq_Coord_BitAnd_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_BitOr_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_BitXor_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Product_non_decreasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_GCD_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Radius_non_decreasing = \&_NumSeq_Coord_Sum_non_decreasing;
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=1,height=1' =>
{ Product => 'A000004', # all zeros
# OEIS-Other: A000004 planepath=Columns,height=1 coordinate_type=Product
# OFFSET
# X => 'A001477', # integers 0 upwards
# Sum => 'A001477', # integers 0 upwards
# DiffXY => 'A001477', # integers 0 upwards
# DiffYX => 'A001489', # negative integers 0 downwards
# AbsDiff => 'A001477', # integers 0 upwards
# Radius => 'A001477', # integers 0 upwards
# RSquared => 'A000290', # squares 0 upwards
# # OEIS-Other: A001477 planepath=Columns,height=1 coordinate_type=X
# # OEIS-Other: A001477 planepath=Columns,height=1 coordinate_type=Sum
# # OEIS-Other: A001489 planepath=Columns,height=1 coordinate_type=DiffYX
# # OEIS-Other: A001477 planepath=Columns,height=1 coordinate_type=DiffXY
# # OEIS-Other: A001477 planepath=Columns,height=1 coordinate_type=AbsDiff
# # OEIS-Other: A001477 planepath=Columns,height=1 coordinate_type=Radius
# # OEIS-Other: A000290 planepath=Columns,height=1 coordinate_type=RSquared
},
'n_start=0,height=2' =>
{ X => 'A004526', # 0,0,1,1,2,2,etc, as per Math::NumSeq::Runs 2rep
Y => 'A000035', # 0,1 repeating OFFSET=0
# OEIS-Other: A004526 planepath=Columns,height=2,n_start=0 coordinate_type=X
# OEIS-Other: A000035 planepath=Columns,height=2,n_start=0 coordinate_type=Y
},
};
}
{ package Math::PlanePath::Diagonals;
use constant _NumSeq_Coord_Sum_non_decreasing => 1; # X+Y diagonals
sub _NumSeq_Coord_SumAbs_non_decreasing {
my ($self) = @_;
return ($self->{'x_start'} >= 0 && $self->{'y_start'} >= 0);
}
# these irrespective where x_start,y_start make x_minimum(),y_minimum()
use constant _NumSeq_Coord_BitAnd_min => 0; # when all diff bits
use constant _NumSeq_Coord_BitXor_min => 0; # when X=Y
use constant _NumSeq_Coord_oeis_anum =>
{
'direction=down,n_start=1,x_start=1,y_start=0' =>
{ Numerator => 'A164306', # T(n,k) = k/GCD(n,k) n,k>=1 offset=1
Denominator => 'A167192', # T(n,k) = (n-k)/GCD(n,k) n,k>=1 offset=1
# OEIS-Catalogue: A164306 planepath=Diagonals,x_start=1,y_start=0 coordinate_type=Numerator
# OEIS-Catalogue: A167192 planepath=Diagonals,x_start=1,y_start=0 coordinate_type=Denominator
},
'direction=down,n_start=0,x_start=0,y_start=0' =>
{ X => 'A002262', # runs 0toN 0, 0,1, 0,1,2, etc
Y => 'A025581', # runs Nto0 0, 1,0, 2,1,0, 3,2,1,0 descend
Sum => 'A003056', # 0, 1,1, 2,2,2, 3,3,3,3
SumAbs => 'A003056', # same
Product => 'A004247', # 0, 0,0,0, 1, 0,0, 2,2, 0,0, 3,4,5, 0,0
DiffYX => 'A114327', # Y-X by anti-diagonals
AbsDiff => 'A049581', # abs(Y-X) by anti-diagonals
RSquared => 'A048147', # x^2+y^2 by diagonals
BitAnd => 'A004198', # X bitand Y
BitOr => 'A003986', # X bitor Y, cf A006583 diagonal totals
BitXor => 'A003987', # cf A006582 X xor Y diagonal totals
GCD => 'A109004', # GCD(x,y) by diagonals, (0,0) at n=0
Min => 'A004197', # X,Y>=0, runs 0toNto0,0toNNto0
MinAbs => 'A004197', # MinAbs=Min
Max => 'A003984',
MaxAbs => 'A003984', # MaxAbs=Max
HammingDist => 'A101080',
# OEIS-Other: A002262 planepath=Diagonals,n_start=0 coordinate_type=X
# OEIS-Other: A025581 planepath=Diagonals,n_start=0 coordinate_type=Y
# OEIS-Other: A003056 planepath=Diagonals,n_start=0 coordinate_type=Sum
# OEIS-Other: A003056 planepath=Diagonals,n_start=0 coordinate_type=SumAbs
# OEIS-Catalogue: A004247 planepath=Diagonals,n_start=0 coordinate_type=Product
# OEIS-Catalogue: A114327 planepath=Diagonals,n_start=0 coordinate_type=DiffYX
# OEIS-Catalogue: A049581 planepath=Diagonals,n_start=0 coordinate_type=AbsDiff
# OEIS-Catalogue: A048147 planepath=Diagonals,n_start=0 coordinate_type=RSquared
# OEIS-Catalogue: A004198 planepath=Diagonals,n_start=0 coordinate_type=BitAnd
# OEIS-Catalogue: A003986 planepath=Diagonals,n_start=0 coordinate_type=BitOr
# OEIS-Catalogue: A003987 planepath=Diagonals,n_start=0 coordinate_type=BitXor
# OEIS-Catalogue: A109004 planepath=Diagonals,n_start=0 coordinate_type=GCD
# OEIS-Catalogue: A004197 planepath=Diagonals,n_start=0 coordinate_type=Min
# OEIS-Other: A004197 planepath=Diagonals,n_start=0 coordinate_type=MinAbs
# OEIS-Catalogue: A003984 planepath=Diagonals,n_start=0 coordinate_type=Max
# OEIS-Other: A003984 planepath=Diagonals,n_start=0 coordinate_type=MaxAbs
# OEIS-Catalogue: A101080 planepath=Diagonals,n_start=0 coordinate_type=HammingDist
},
'direction=up,n_start=0,x_start=0,y_start=0' =>
{ X => 'A025581', # \ opposite of direction="down"
Y => 'A002262', # /
Sum => 'A003056', # \
SumAbs => 'A003056', # | same as direction="down'
Product => 'A004247', # |
AbsDiff => 'A049581', # |
RSquared => 'A048147', # /
DiffXY => 'A114327', # transposed from direction="down"
BitAnd => 'A004198', # X bitand Y
BitOr => 'A003986', # X bitor Y, cf A006583 diagonal totals
BitXor => 'A003987', # cf A006582 X xor Y diagonal totals
GCD => 'A109004', # GCD(x,y) by diagonals, (0,0) at n=0
HammingDist => 'A101080',
# OEIS-Other: A025581 planepath=Diagonals,direction=up,n_start=0 coordinate_type=X
# OEIS-Other: A002262 planepath=Diagonals,direction=up,n_start=0 coordinate_type=Y
# OEIS-Other: A003056 planepath=Diagonals,direction=up,n_start=0 coordinate_type=Sum
# OEIS-Other: A003056 planepath=Diagonals,direction=up,n_start=0 coordinate_type=SumAbs
# OEIS-Other: A004247 planepath=Diagonals,direction=up,n_start=0 coordinate_type=Product
# OEIS-Other: A114327 planepath=Diagonals,direction=up,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A049581 planepath=Diagonals,direction=up,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A048147 planepath=Diagonals,direction=up,n_start=0 coordinate_type=RSquared
# OEIS-Other: A004198 planepath=Diagonals,direction=up,n_start=0 coordinate_type=BitAnd
# OEIS-Other: A003986 planepath=Diagonals,direction=up,n_start=0 coordinate_type=BitOr
# OEIS-Other: A003987 planepath=Diagonals,direction=up,n_start=0 coordinate_type=BitXor
# OEIS-Other: A109004 planepath=Diagonals,direction=up,n_start=0 coordinate_type=GCD
# OEIS-Other: A101080 planepath=Diagonals,direction=up,n_start=0 coordinate_type=HammingDist
},
'direction=down,n_start=1,x_start=1,y_start=1' =>
{ Product => 'A003991', # X*Y starting (1,1) n=1
GCD => 'A003989', # GCD by diagonals starting (1,1) n=1
Min => 'A003983', # X,Y>=1
MinAbs => 'A003983', # MinAbs=Min
Max => 'A051125', # X,Y>=1
MaxAbs => 'A051125', # MaxAbs=Max
IntXY => 'A004199', # X>=0,Y>=0, X/Y round towards zero
# OEIS-Catalogue: A003991 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=Product
# OEIS-Catalogue: A003989 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=GCD
# OEIS-Catalogue: A003983 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=Min
# OEIS-Other: A003983 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=MinAbs
# OEIS-Catalogue: A051125 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=Max
# OEIS-Other: A051125 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=MaxAbs
# OEIS-Catalogue: A004199 planepath=Diagonals,x_start=1,y_start=1 coordinate_type=IntXY
# cf A003990 LCM starting (1,1) n=1
# A003992 X^Y power starting (1,1) n=1
},
'direction=up,n_start=1,x_start=1,y_start=1' =>
{ Product => 'A003991', # X*Y starting (1,1) n=1
GCD => 'A003989', # GCD by diagonals starting (1,1) n=1
IntXY => 'A003988', # Int(X/Y) starting (1,1) n=1
# OEIS-Other: A003991 planepath=Diagonals,direction=up,x_start=1,y_start=1 coordinate_type=Product
# OEIS-Other: A003989 planepath=Diagonals,direction=up,x_start=1,y_start=1 coordinate_type=GCD
# OEIS-Catalogue: A003988 planepath=Diagonals,direction=up,x_start=1,y_start=1 coordinate_type=IntXY
# num,den of reduction of A004736/A002260 which is run1toK/runKto1.
Numerator => 'A112543', # 1,2,1,3,1,1,4,3,2,1,5,2,1,1,1,6,
Denominator => 'A112544', # 1,1,2,1,1,3,1,2,3,4,1,1,1,2,5,1,
# OEIS-Catalogue: A112543 planepath=Diagonals,direction=up,x_start=1,y_start=1 coordinate_type=Numerator
# OEIS-Catalogue: A112544 planepath=Diagonals,direction=up,x_start=1,y_start=1 coordinate_type=Denominator
},
};
}
{ package Math::PlanePath::DiagonalsAlternating;
use constant _NumSeq_Coord_Sum_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_SumAbs_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=0' =>
{ Sum => 'A003056', # 0, 1,1, 2,2,2, 3,3,3,3
SumAbs => 'A003056', # same
Product => 'A004247', # 0, 0,0,0, 1, 0,0, 2,2, 0,0, 3,4,5, 0,0
AbsDiff => 'A049581', # abs(Y-X) by anti-diagonals
RSquared => 'A048147', # x^2+y^2 by diagonals
BitAnd => 'A004198', # X bitand Y
BitOr => 'A003986', # X bitor Y, cf A006583 diagonal totals
BitXor => 'A003987', # cf A006582 X xor Y diagonal totals
Min => 'A004197', # runs 0toNto0,0toNNto0
MinAbs => 'A004197', # MinAbs=Min
Max => 'A003984',
MaxAbs => 'A003984', # MaxAbs=Max
HammingDist => 'A101080',
# OEIS-Other: A003056 planepath=DiagonalsAlternating,n_start=0 coordinate_type=Sum
# OEIS-Other: A003056 planepath=DiagonalsAlternating,n_start=0 coordinate_type=SumAbs
# OEIS-Other: A004247 planepath=DiagonalsAlternating,n_start=0 coordinate_type=Product
# OEIS-Other: A049581 planepath=DiagonalsAlternating,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A048147 planepath=DiagonalsAlternating,n_start=0 coordinate_type=RSquared
# OEIS-Other: A004198 planepath=DiagonalsAlternating,n_start=0 coordinate_type=BitAnd
# OEIS-Other: A003986 planepath=DiagonalsAlternating,n_start=0 coordinate_type=BitOr
# OEIS-Other: A003987 planepath=DiagonalsAlternating,n_start=0 coordinate_type=BitXor
# OEIS-Other: A004197 planepath=DiagonalsAlternating,n_start=0 coordinate_type=Min
# OEIS-Other: A004197 planepath=DiagonalsAlternating,n_start=0 coordinate_type=MinAbs
# OEIS-Other: A003984 planepath=DiagonalsAlternating,n_start=0 coordinate_type=Max
# OEIS-Other: A003984 planepath=DiagonalsAlternating,n_start=0 coordinate_type=MaxAbs
# OEIS-Other: A101080 planepath=DiagonalsAlternating,n_start=0 coordinate_type=HammingDist
},
};
}
{ package Math::PlanePath::DiagonalsOctant;
use constant _NumSeq_Coord_Sum_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_SumAbs_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_oeis_anum =>
{ 'direction=down,n_start=0' =>
{ X => 'A055087', # 0, 0,1, 0,1, 0,1,2, 0,1,2, etc
Min => 'A055087', # X<=Y so Min=X
MinAbs => 'A055087', # MinAbs=Min
Sum => 'A055086', # reps floor(n/2)+1
SumAbs => 'A055086', # same
DiffYX => 'A082375', # step=2 k to 0
# OEIS-Catalogue: A055087 planepath=DiagonalsOctant,n_start=0 coordinate_type=X
# OEIS-Other: A055087 planepath=DiagonalsOctant,n_start=0 coordinate_type=Min
# OEIS-Other: A055087 planepath=DiagonalsOctant,n_start=0 coordinate_type=MinAbs
# OEIS-Catalogue: A055086 planepath=DiagonalsOctant,n_start=0 coordinate_type=Sum
# OEIS-Other: A055086 planepath=DiagonalsOctant,n_start=0 coordinate_type=SumAbs
# OEIS-Catalogue: A082375 planepath=DiagonalsOctant,n_start=0 coordinate_type=DiffYX
},
'direction=up,n_start=0' =>
{ Sum => 'A055086', # reps floor(n/2)+1
SumAbs => 'A055086', # same
# OEIS-Other: A055086 planepath=DiagonalsOctant,direction=up,n_start=0 coordinate_type=Sum
# OEIS-Other: A055086 planepath=DiagonalsOctant,direction=up,n_start=0 coordinate_type=SumAbs
},
};
}
# { package Math::PlanePath::MPeaks;
# }
# { package Math::PlanePath::Staircase;
# }
# { package Math::PlanePath::StaircaseAlternating;
# }
{ package Math::PlanePath::Corner;
sub _NumSeq_Coord_Max_non_decreasing {
my ($self) = @_;
# non-decreasing when wider=0 or 1
return ($self->{'wider'} <= 1);
}
use constant _NumSeq_Coord_oeis_anum =>
{ 'wider=0,n_start=1' =>
{ Sum => 'A213088', # manhatten X+Y
SumAbs => 'A213088',
# OEIS-Catalogue: A213088 planepath=Corner coordinate_type=Sum
# OEIS-Other: A213088 planepath=Corner coordinate_type=SumAbs
},
'wider=0,n_start=0' =>
{ DiffXY => 'A196199', # runs -n to n
AbsDiff => 'A053615', # runs n..0..n
Max => 'A000196', # n repeated 2n+1 times, floor(sqrt(N))
MaxAbs => 'A000196', # MaxAbs=Max
# OEIS-Other: A196199 planepath=Corner,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A053615 planepath=Corner,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A000196 planepath=Corner,n_start=0 coordinate_type=Max
# OEIS-Other: A000196 planepath=Corner,n_start=0 coordinate_type=MaxAbs
# Not quite, A053188 has extra initial 0
# AbsDiff => 'A053188', # distance to nearest square
},
};
}
{ package Math::PlanePath::PyramidRows;
*_NumSeq_Coord_Min_non_decreasing = \&_NumSeq_Coord_Y_increasing;
# Max==Y and Y is non-decreasing when
# step=0 align=any
# step=1 align=any
# step=2 align=left or centre
# step>2 align=left
sub _NumSeq_Coord_Max_non_decreasing {
my ($self) = @_;
return ($self->{'step'} <= 1
|| ($self->{'step'} == 2 && $self->{'align'} eq 'centre')
|| $self->{'align'} eq 'left');
}
sub _NumSeq_Coord_MaxAbs_non_decreasing {
my ($self) = @_;
return ($self->{'step'} <= 1
|| ($self->{'step'} == 2 && $self->{'align'} eq 'centre'));
}
*_NumSeq_Coord_Sum_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_Y_increasing;
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return ($self->{'align'} eq 'left' ? - $self->{'step'}
: $self->{'align'} eq 'centre' ? - int($self->{'step'}/2)
: 0); # right
}
sub _NumSeq_Coord_FracXY_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 : 1); # step=0 X=0 frac=0 always
}
*_NumSeq_FracXY_max_is_supremum = \&_NumSeq_Coord_FracXY_max;
sub _NumSeq_Coord_FracXY_integer {
my ($self) = @_;
return ($self->{'step'} == 0 ? 1 : 0); # step=0 X=0 frac=0 always
}
sub _NumSeq_Coord_Radius_integer {
my ($self) = @_;
return ($self->{'step'} == 0);
}
sub _NumSeq_Coord_Y_increasing {
my ($self) = @_;
return ($self->{'step'} == 0
? 1 # column X=0,Y=N
: 0);
}
*_NumSeq_Coord_DiffYX_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_Max_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_BitOr_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_BitXor_increasing = \&_NumSeq_Coord_Y_increasing;
*_NumSeq_Coord_GCD_increasing = \&_NumSeq_Coord_Y_increasing;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
*_NumSeq_Coord_X_non_decreasing = \&_NumSeq_Coord_Y_increasing; # X=0 always
*_NumSeq_Coord_Product_non_decreasing = \&_NumSeq_Coord_Y_increasing; # N*0=0
# step=0 constant Numerator=0
sub _NumSeq_Coord_Numerator_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 : undef);
}
# step=0 has Y=0 so BitAnd=0 always
*_NumSeq_Coord_BitAnd_max = \&_NumSeq_Coord_Numerator_max;
*_NumSeq_Coord_BitAnd_non_decreasing = \&_NumSeq_Coord_Y_increasing;
# cf A050873 GCD(X+1,Y+1) by rows n>=1 k=1..n, x_start=1,y_start=1
# A051173 LCM(X+1,Y+1) by rows n>=1 k=1..n, x_start=1,y_start=1
#
# Maybe with x_start,y_start to go by rows starting from 1.
# Denominator => 'A164306', # T(n,k) = k/GCD(n,k) n,k>=1 offset=1
# # OEIS-Catalogue: A164306 planepath=PyramidRows,step=1,x_start=1,y_start=1 coordinate_type=Denominator
# Denominator => 'A167192', # T(n,k) = (n-k)/GCD(n,k) n,k>=1 offset=1
# # OEIS-Catalogue: A167192 planepath=PyramidRows,step=1,x_start=1,y_start=1,align=left coordinate_type=Numerator
#
use constant _NumSeq_Coord_oeis_anum =>
{
# PyramidRows step=0 is trivial X=0,Y=N
do {
my $href = { X => 'A000004', # all-zeros
Product => 'A000004', # all-zeros
# OEIS-Other: A000004 planepath=PyramidRows,step=0 coordinate_type=X
# OEIS-Other: A000004 planepath=PyramidRows,step=0 coordinate_type=Product
};
('step=0,align=centre' => $href,
'step=0,align=right' => $href,
'step=0,align=left' => $href,
);
},
do {
my $href = { X => 'A000004', # all zeros
Min => 'A000004', # Min=X
Y => 'A001477', # integers Y=0,1,2,etc
Max => 'A001477', # Max=Y
MaxAbs => 'A001477', # MaxAbs=Max
Sum => 'A001477', # Sum=Y
DiffYX => 'A001477', # DiffYX=Y
DiffXY => 'A001489', # negatives 0,-1,-2,etc
AbsDiff => 'A001477', # AbsDiff=Y
Product => 'A000004', # Product=0
Radius => 'A001477', # Radius=Y
GCD => 'A001477', # GCD=Y
RSquared => 'A000290', # n^2
TRSquared => 'A033428', # 3*n^2
BitAnd => 'A000004', # BitAnd=0
BitOr => 'A001477', # BitOr=Y
BitXor => 'A001477', # BitXor=Y
# OEIS-Other: A000004 planepath=PyramidRows,step=0,n_start=0 coordinate_type=X
# OEIS-Other: A000004 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Min
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Y
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Max
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=MaxAbs
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Sum
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A001489 planepath=PyramidRows,step=0,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A000004 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Product
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=Radius
# OEIS-Other: A001489 planepath=PyramidRows,step=0,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A000290 planepath=PyramidRows,step=0,n_start=0 coordinate_type=RSquared
# OEIS-Other: A033428 planepath=PyramidRows,step=0,n_start=0 coordinate_type=TRSquared
# OEIS-Other: A000004 planepath=PyramidRows,step=0,n_start=0 coordinate_type=BitAnd
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=BitOr
# OEIS-Other: A001477 planepath=PyramidRows,step=0,n_start=0 coordinate_type=BitXor
};
('step=0,align=centre,n_start=0' => $href,
'step=0,align=right,n_start=0' => $href,
'step=0,align=left,n_start=0' => $href,
);
},
# PyramidRows step=1
# cf A050873 GCD triangle starting (1,1) n=1
# A051173 LCM triangle starting (1,1) n=1
# A003991 X*Y product starting (1,1) n=1
# A001316 count of occurrences of n as BitOr
do {
my $href =
{ X => 'A002262', # 0, 0,1, 0,1,2, etc (Diagonals)
Min => 'A002262', # X<=Y always
Y => 'A003056', # 0, 1,1, 2,2,2, 3,3,3,3 (Diagonals)
Max => 'A003056', # Max=Y as Y>=X always
MaxAbs => 'A003056', # MaxAbs=Max as Y>=0 always
DiffYX => 'A025581', # descending N to 0 (Diagonals)
AbsDiff => 'A025581', # absdiff same
Sum => 'A051162', # triangle X+Y for X=0 to Y inclusive
SumAbs => 'A051162', # sumabs same
Product => 'A079904',
RSquared => 'A069011', # triangle X^2+Y^2 for X=0 to Y inclusive
GCD => 'A109004', # same as by diagonals
BitAnd => 'A080099',
BitOr => 'A080098',
BitXor => 'A051933',
};
('step=1,align=centre,n_start=0' => $href,
'step=1,align=right,n_start=0' => $href,
);
# OEIS-Other: A002262 planepath=PyramidRows,step=1,n_start=0 coordinate_type=X
# OEIS-Other: A002262 planepath=PyramidRows,step=1,n_start=0 coordinate_type=Min
# OEIS-Other: A003056 planepath=PyramidRows,step=1,n_start=0 coordinate_type=Y
# OEIS-Other: A003056 planepath=PyramidRows,step=1,n_start=0 coordinate_type=Max
# OEIS-Other: A003056 planepath=PyramidRows,step=1,n_start=0 coordinate_type=MaxAbs
# OEIS-Other: A025581 planepath=PyramidRows,step=1,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A025581 planepath=PyramidRows,step=1,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A051162 planepath=PyramidRows,step=1,n_start=0 coordinate_type=Sum
# OEIS-Other: A051162 planepath=PyramidRows,step=1,n_start=0 coordinate_type=SumAbs
# OEIS-Catalogue: A079904 planepath=PyramidRows,step=1,n_start=0 coordinate_type=Product
# OEIS-Catalogue: A069011 planepath=PyramidRows,step=1,n_start=0 coordinate_type=RSquared
# OEIS-Other: A109004 planepath=PyramidRows,step=1,n_start=0 coordinate_type=GCD
# OEIS-Catalogue: A080099 planepath=PyramidRows,step=1,n_start=0 coordinate_type=BitAnd
# OEIS-Catalogue: A080098 planepath=PyramidRows,step=1,n_start=0 coordinate_type=BitOr
# OEIS-Catalogue: A051933 planepath=PyramidRows,step=1,n_start=0 coordinate_type=BitXor
# OEIS-Other: A002262 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=X
# OEIS-Other: A003056 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=Y
# OEIS-Other: A025581 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A025581 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A051162 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=Sum
# OEIS-Other: A051162 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=SumAbs
# OEIS-Other: A079904 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=Product
# OEIS-Other: A069011 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=RSquared
# OEIS-Other: A080099 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=BitAnd
# OEIS-Other: A080098 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=BitOr
# OEIS-Other: A051933 planepath=PyramidRows,step=1,align=right,n_start=0 coordinate_type=BitXor
},
# 'step=1,align=left,n_start=0' =>
# { AbsX => 'A025581', # descending runs n to 0
# },
# PyramidRows step=2
'step=2,align=centre,n_start=0' =>
{ X => 'A196199', # runs -n to n
Min => 'A196199', # X since X 'A000196', # n appears 2n+1 times, starting 0
Max => 'A000196', # Y since X 'A053186', # runs 0 to 2n
AbsX => 'A053615', # runs n to 0 to n
# OEIS-Catalogue: A196199 planepath=PyramidRows,n_start=0 coordinate_type=X
# OEIS-Other: A196199 planepath=PyramidRows,n_start=0 coordinate_type=Min
# OEIS-Catalogue: A000196 planepath=PyramidRows,n_start=0 coordinate_type=Y
# OEIS-Other: A000196 planepath=PyramidRows,n_start=0 coordinate_type=Max
# OEIS-Other: A053186 planepath=PyramidRows,n_start=0 coordinate_type=Sum
# OEIS-Other: A053615 planepath=PyramidRows,n_start=0 coordinate_type=AbsX
# # Not quite, extra initial 0
# DiffYX => 'A068527', # dist to next square
# AbsDiff => 'A068527', # same since Y-X>0
},
'step=2,align=right,n_start=0' =>
{ X => 'A053186', # runs 0 to 2n
Y => 'A000196', # n appears 2n+1 times, starting 0
DiffXY => 'A196199', # runs -n to n
AbsDiff => 'A053615', # n..0..n, distance to pronic
# OEIS-Other: A053186 planepath=PyramidRows,align=right,n_start=0 coordinate_type=X
# OEIS-Other: A000196 planepath=PyramidRows,align=right,n_start=0 coordinate_type=Y
# OEIS-Other: A196199 planepath=PyramidRows,align=right,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A053615 planepath=PyramidRows,align=right,n_start=0 coordinate_type=AbsDiff
},
'step=2,align=left,n_start=0' =>
{ X => '', # runs -2n+1 to 0
Y => 'A000196', # n appears 2n+1 times, starting 0
Sum => 'A196199', # -n to n
# OEIS-Other: A000196 planepath=PyramidRows,align=left,n_start=0 coordinate_type=Y
# OEIS-Other: A196199 planepath=PyramidRows,align=left,n_start=0 coordinate_type=Sum
# Not quite, A068527 doesn't have two initial 0s
# AbsX => 'A068527', # dist to next square
# # OEIS-Other: A068527 planepath=PyramidRows,align=left,n_start=0 coordinate_type=AbsX
},
# PyramidRows step=3
do {
my $href =
{ Y => 'A180447', # n appears 3n+1 times, starting 0
};
('step=3,align=centre,n_start=0' => $href,
'step=3,align=right,n_start=0' => $href,
);
# OEIS-Catalogue: A180447 planepath=PyramidRows,step=3,n_start=0 coordinate_type=Y
# OEIS-Other: A180447 planepath=PyramidRows,step=3,align=right,n_start=0 coordinate_type=Y
},
'step=3,align=left,n_start=0' =>
{ Y => 'A180447', # n appears 3n+1 times, starting 0
Max => 'A180447', # Y since X
{ X => 'A060511', # amount exceeding hexagonal number
},
# OEIS-Catalogue: A060511 planepath=PyramidRows,step=4,align=right,n_start=0 coordinate_type=X
};
}
{ package Math::PlanePath::PyramidSides;
use constant _NumSeq_Coord_SumAbs_non_decreasing => 1;
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=0' =>
{ X => 'A196199', # runs -n to n
SumAbs => 'A000196', # n appears 2n+1 times, starting 0
# OEIS-Other: A196199 planepath=PyramidSides,n_start=0 coordinate_type=X
# OEIS-Other: A000196 planepath=PyramidSides,n_start=0 coordinate_type=SumAbs
AbsX => 'A053615', # runs n to 0 to n
# OEIS-Other: A053615 planepath=PyramidSides,n_start=0 coordinate_type=AbsX
},
};
}
{ package Math::PlanePath::CellularRule;
# single cell
# 111 -> any
# 110 -> any
# 101 -> any
# 100 -> 0 initial
# 011 -> any
# 010 -> 0 initial
# 001 -> 0 initial
# 000 -> 0
# so (rule & 0x17) == 0
#
# right 2 cell line 0x54,74,D4,F4
# 111 -> any
# 110 -> 1
# 101 -> any
# 100 -> 1
# 011 -> 0
# 010 -> 1
# 001 -> 0
# 000 -> 0
# so (rule & 0x5F) == 0x54
#
sub _NumSeq_Coord_X_increasing {
my ($self) = @_;
### CellularRule _NumSeq_Coord_X_increasing() rule: $self->{'rule'}
return (($self->{'rule'} & 0x17) == 0 # single cell only
? 1
: 0);
}
sub _NumSeq_Coord_Sum_increasing {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
|| ($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1
: 0);
}
*_NumSeq_Coord_Min_increasing = \&_NumSeq_Coord_Sum_increasing; # Min=X
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_Sum_increasing;
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_Sum_increasing;
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_Radius_increasing;
*_NumSeq_Coord_Y_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_Max_increasing = \&_NumSeq_Coord_X_increasing; # Max==Y
*_NumSeq_Coord_Product_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_DiffXY_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_DiffYX_increasing = \&_NumSeq_Coord_X_increasing;
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_X_increasing;
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
sub _NumSeq_Coord_X_non_decreasing {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
|| ($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1
: 0);
}
*_NumSeq_Coord_Min_non_decreasing = \&_NumSeq_Coord_X_non_decreasing; # Min=X
sub _NumSeq_Coord_Product_non_decreasing {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
|| ($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1
: 0);
}
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max==Y
sub _NumSeq_Coord_BitAnd_max {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
|| ($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 0
: undef);
}
sub _NumSeq_Coord_Parity_max {
my ($self) = @_;
return (($self->{'rule'} & 0x17) == 0 # single cell only
? 0 # X=0,Y=0 even
: 1);
}
use constant _NumSeq_Coord_oeis_anum =>
{
# rule=14,46,142,174 left 2
# rule=84,116,212,244 right 2
do {
my $lr2 = { Y => 'A076938', # 0,1,1,2,2,3,3,...
# OEIS-Other: A076938 planepath=CellularRule,rule=14 coordinate_type=Y
# OEIS-Other: A076938 planepath=CellularRule,rule=174 coordinate_type=Y
};
('rule=14,n_start=1' => $lr2,
'rule=46,n_start=1' => $lr2,
'rule=142,n_start=1' => $lr2,
'rule=174,n_start=1' => $lr2,
'rule=84,n_start=1' => $lr2,
'rule=116,n_start=1' => $lr2,
'rule=212,n_start=1' => $lr2,
'rule=144,n_start=1' => $lr2,
)
},
};
}
{ package Math::PlanePath::CellularRule::OneTwo;
sub _NumSeq_Coord_Sum_increasing {
my ($self) = @_;
return ($self->{'sign'} > 0); # when to the right
}
*_NumSeq_Coord_SumAbs_increasing = \&_NumSeq_Coord_Sum_increasing;
*_NumSeq_Coord_Radius_increasing = \&_NumSeq_Coord_Sum_increasing;
*_NumSeq_Coord_TRadius_increasing = \&_NumSeq_Coord_Radius_increasing;
sub _NumSeq_Coord_X_non_decreasing {
my ($self) = @_;
return ($self->{'sign'} > 0); # yes when to the right
}
*_NumSeq_Coord_Min_non_decreasing = \&_NumSeq_Coord_X_non_decreasing; # Min=X
*_NumSeq_Coord_Product_non_decreasing = \&_NumSeq_Coord_X_non_decreasing;
*_NumSeq_Coord_BitAnd_non_decreasing = \&_NumSeq_Coord_X_non_decreasing;
*_NumSeq_Coord_BitOr_non_decreasing = \&_NumSeq_Coord_X_non_decreasing;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
sub _NumSeq_Coord_MinAbs_non_decreasing {
my ($self) = @_;
return ($self->{'sign'} > 0); # yes when to the right
}
use constant _NumSeq_Coord_oeis_anum =>
{ 'align=left,n_start=0' =>
{ Y => 'A004396', # one even two odd
Max => 'A004396', # Max=Y
SumAbs => 'A131452', # a(3n)=4n, a(3n+1)=4n+2, a(3n+2)=4n+1.
DiffYX => 'A131452', # X<0 so Y-X=abs(Y)+abs(X)
# OEIS-Catalogue: A004396 planepath=CellularRule,rule=6,n_start=0 coordinate_type=Y
# OEIS-Other: A004396 planepath=CellularRule,rule=166,n_start=0 coordinate_type=Max
# OEIS-Catalogue: A131452 planepath=CellularRule,rule=6,n_start=0 coordinate_type=SumAbs
# OEIS-Other: A131452 planepath=CellularRule,rule=166,n_start=0 coordinate_type=SumAbs
# Maybe, but OFFSET in fractions?
# Sum => 'A022003', # 1/999 decimal 0,0,1,0,0,1
# # OEIS-Other: A022003 planepath=CellularRule,rule=166,n_start=0 coordinate_type=Sum
},
'align=right,n_start=0' =>
{ X => 'A004523', # 0,0,1,2,2,3 two even, one odd
Min => 'A004523', # Min=X
BitAnd => 'A004523', # BitAnd=X
Y => 'A004396', # one even two odd
Max => 'A004396', # Max=Y
BitOr => 'A004396', # BitOr=Y
SumAbs => 'A004773', # 0,1,2 mod 4
# OEIS-Catalogue: A004523 planepath=CellularRule,rule=20,n_start=0 coordinate_type=X
# OEIS-Other: A004523 planepath=CellularRule,rule=20,n_start=0 coordinate_type=Min
# OEIS-Other: A004523 planepath=CellularRule,rule=20,n_start=0 coordinate_type=BitAnd
# OEIS-Other: A004396 planepath=CellularRule,rule=20,n_start=0 coordinate_type=Y
# OEIS-Other: A004396 planepath=CellularRule,rule=180,n_start=0 coordinate_type=Max
# OEIS-Other: A004396 planepath=CellularRule,rule=180,n_start=0 coordinate_type=BitOr
# OEIS-Catalogue: A004773 planepath=CellularRule,rule=20,n_start=0 coordinate_type=SumAbs
# OEIS-Other: A004773 planepath=CellularRule,rule=180,n_start=0 coordinate_type=SumAbs
},
};
}
{ package Math::PlanePath::CellularRule::Line;
sub _NumSeq_Coord_Radius_integer {
my ($path) = @_;
# centre Radius=Y so integer, otherwise Radius=sqrt(2)*Y not integer
return ($path->{'align'} eq 'centre');
}
use constant _NumSeq_Coord_Y_increasing => 1; # line upwards
use constant _NumSeq_Coord_Max_increasing => 1; # Max=Y
use constant _NumSeq_Coord_Radius_increasing => 1; # line upwards
use constant _NumSeq_Coord_TRadius_increasing => 1; # line upwards
sub _NumSeq_Coord_TRadius_integer {
my ($path) = @_;
return ($path->{'sign'} != 0); # left or right sloping
}
sub _NumSeq_Coord_X_increasing {
my ($path) = @_;
return ($path->{'sign'} >= 1); # X=Y diagonal
}
sub _NumSeq_Coord_X_non_decreasing {
my ($path) = @_;
return ($path->{'sign'} >= 0); # X=0 vertical or X=Y diagonal
}
*_NumSeq_Coord_Min_non_decreasing = \&_NumSeq_Coord_X_non_decreasing; # Min=X
*_NumSeq_Coord_Min_increasing = \&_NumSeq_Coord_X_increasing; # Min=X
sub _NumSeq_Coord_Sum_increasing {
my ($path) = @_;
return ($path->{'sign'} == -1
? 0 # X=-Y so X+Y=0
: 1); # X=0 so X+Y=Y, or X=Y so X+Y=2Y
}
use constant _NumSeq_Coord_Sum_non_decreasing => 1; # line upwards
use constant _NumSeq_Coord_SumAbs_increasing => 1; # line upwards
sub _NumSeq_Coord_Product_increasing {
my ($path) = @_;
return ($path->{'sign'} > 0
? 1 # X=Y so X*Y=Y^2
: 0); # X=0 so X*Y=0, or X=-Y so X*Y=-(Y^2)
}
sub _NumSeq_Coord_Product_non_decreasing {
my ($path) = @_;
return ($path->{'sign'} >= 0
? 1 # X=Y so X*Y=Y^2
: 0); # X=0 so X*Y=0, or X=-Y so X*Y=-(Y^2)
}
# sign=1 X=Y so X-Y=0 always, non-decreasing
# sign=0 X=0 so Y-X=Y, increasing
# sign=-1 X=-Y so Y-X=2*Y, increasing
sub _NumSeq_Coord_DiffXY_non_decreasing {
my ($path) = @_;
return ($path->{'sign'} == 1 ? 1 # X-Y=0 always
: 0);
}
sub _NumSeq_Coord_DiffYX_increasing {
my ($path) = @_;
return ($path->{'sign'} == 1 ? 0 : 1);
}
*_NumSeq_Coord_AbsDiff_increasing = \&_NumSeq_Coord_DiffYX_increasing;
use constant _NumSeq_Coord_DiffYX_non_decreasing => 1; # Y-X >= 0 always
use constant _NumSeq_Coord_AbsDiff_non_decreasing => 1; # Y-X >= 0 always
use constant _NumSeq_Coord_GCD_increasing => 1; # GCD==Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
sub _NumSeq_Coord_Parity_max {
my ($path) = @_;
return ($path->{'align'} eq 'centre' ? 1 : 0);
}
sub _NumSeq_Coord_Numerator_min {
my ($path) = @_;
return ($path->{'align'} eq 'left'
? -1
: 0);
}
sub _NumSeq_Coord_Numerator_max {
my ($path) = @_;
return ($path->{'align'} eq 'right'
? 1 # right X=Y so 1/1 except for 0/0
: 0);
}
sub _NumSeq_Coord_Numerator_non_decreasing {
my ($path) = @_;
return ($path->{'align'} ne 'left');
}
# Denominator_min => 0; # 0/0 at n_start()
use constant _NumSeq_Coord_Denominator_max => 1;
use constant _NumSeq_Coord_Denominator_non_decreasing => 1;
# left Y bitand -Y twos-complement gives mask of low 1-bits
sub _NumSeq_Coord_BitAnd_non_decreasing {
my ($path) = @_;
return ($path->{'align'} ne 'left'); # centre BitAnd=0, right BitAnd=Y
}
sub _NumSeq_Coord_BitAnd_increasing {
my ($path) = @_;
return ($path->{'align'} eq 'right'); # right BitAnd=Y
}
# left Y bitor -Y twos-complement gives all-1s above low 0-bits
sub _NumSeq_Coord_BitOr_increasing {
my ($path) = @_;
return ($path->{'align'} ne 'left'); # centre,right BitOr = Y
}
sub _NumSeq_Coord_BitXor_min {
my ($path) = @_;
return ($path->{'align'} eq 'left'
? undef
: 0); # right X=Y so BitXor=0 always, centre X=0 so BitXor=Y
}
sub _NumSeq_Coord_BitXor_max {
my ($path) = @_;
return ($path->{'align'} eq 'centre'
? undef # centre X=0 BitXor=Y
: 0); # right X=Y so BitXor=0 always, left negative
}
sub _NumSeq_Coord_BitXor_increasing {
my ($path) = @_;
return ($path->{'align'} eq 'centre'); # centre BitXor=Y
}
# and maximum 0/0=infinity
sub _NumSeq_Coord_IntXY_min {
my ($path) = @_;
return ($path->{'align'} eq 'right'
? 1 # right X=Y so X/Y=1 always
: $path->{'align'} eq 'left'
? -1 # left X=-Y so X/Y=-1 always
: 0);
}
use constant _NumSeq_Coord_FracXY_min => 0; # X=0,+Y,-Y so frac=0
use constant _NumSeq_Coord_FracXY_max => 0;
use constant _NumSeq_Coord_FracXY_integer => 1;
use constant _NumSeq_FracXY_min_is_infimum => 0;
use constant _NumSeq_FracXY_max_is_supremum => 0;
use constant _NumSeq_Coord_oeis_anum =>
{ 'align=left,n_start=0' =>
{ X => 'A001489', # integers negative X=0,-1,-2,etc
Min => 'A001489', # Min=X
Y => 'A001477', # integers Y=0,1,2,etc
Max => 'A001477', # Max=Y
Sum => 'A000004', # all zeros
DiffYX => 'A005843', # even 0,2,4,etc
RSquared => 'A001105', # 2*n^2
TRSquared => 'A016742', # 4*n^2
# OEIS-Other: A001489 planepath=CellularRule,rule=2,n_start=0 coordinate_type=X
# OEIS-Other: A001489 planepath=CellularRule,rule=2,n_start=0 coordinate_type=Min
# OEIS-Other: A001477 planepath=CellularRule,rule=2,n_start=0 coordinate_type=Y
# OEIS-Other: A001477 planepath=CellularRule,rule=2,n_start=0 coordinate_type=Max
# OEIS-Other: A000004 planepath=CellularRule,rule=2,n_start=0 coordinate_type=Sum
# OEIS-Other: A005843 planepath=CellularRule,rule=2,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A001105 planepath=CellularRule,rule=2,n_start=0 coordinate_type=RSquared
# OEIS-Other: A016742 planepath=CellularRule,rule=2,n_start=0 coordinate_type=TRSquared
},
'align=right,n_start=0' =>
{ X => 'A001477', # integers Y=0,1,2,etc
Min => 'A001477', # Min=X
Y => 'A001477', # integers Y=0,1,2,etc
Max => 'A001477', # Max=Y
Sum => 'A005843', # even 0,2,4,etc
DiffYX => 'A000004', # all zeros
DiffXY => 'A000004', # all zeros
RSquared => 'A001105', # 2*n^2
TRSquared => 'A016742', # 4*n^2
# OEIS-Other: A001477 planepath=CellularRule,rule=16,n_start=0 coordinate_type=X
# OEIS-Other: A001477 planepath=CellularRule,rule=16,n_start=0 coordinate_type=Min
# OEIS-Other: A001477 planepath=CellularRule,rule=16,n_start=0 coordinate_type=Y
# OEIS-Other: A001477 planepath=CellularRule,rule=16,n_start=0 coordinate_type=Max
# OEIS-Other: A005843 planepath=CellularRule,rule=16,n_start=0 coordinate_type=Sum
# OEIS-Other: A000004 planepath=CellularRule,rule=16,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A000004 planepath=CellularRule,rule=16,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A001105 planepath=CellularRule,rule=16,n_start=0 coordinate_type=RSquared
# OEIS-Other: A016742 planepath=CellularRule,rule=16,n_start=0 coordinate_type=TRSquared
},
# same as PyramidRows step=0
'align=centre,n_start=0' =>
Math::PlanePath::PyramidRows->_NumSeq_Coord_oeis_anum()->{'step=0,align=centre,n_start=0'},
# OEIS-Other: A000004 planepath=CellularRule,rule=4,n_start=0 coordinate_type=X
# OEIS-Other: A000004 planepath=CellularRule,rule=4,n_start=0 coordinate_type=Min
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=Y
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=Max
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=Sum
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=DiffYX
# OEIS-Other: A001489 planepath=CellularRule,rule=4,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=AbsDiff
# OEIS-Other: A001477 planepath=CellularRule,rule=4,n_start=0 coordinate_type=Radius
# OEIS-Other: A001489 planepath=CellularRule,rule=4,n_start=0 coordinate_type=DiffXY
# OEIS-Other: A000290 planepath=CellularRule,rule=4,n_start=0 coordinate_type=RSquared
# OEIS-Other: A033428 planepath=CellularRule,rule=4,n_start=0 coordinate_type=TRSquared
};
# CellularRule starts i=1 value=0, but A000027 is OFFSET=1 value=1
# } elsif ($planepath_object->isa('Math::PlanePath::CellularRule::Line')) {
# # for all "rule" parameter values
# if ($coordinate_type eq 'Y'
# || ($planepath_object->{'sign'} == 0
# && ($coordinate_type eq 'Sum'
# || $coordinate_type eq 'DiffYX'
# || $coordinate_type eq 'AbsDiff'
# || $coordinate_type eq 'Radius'))) {
# return 'A000027'; # natural numbers 1,2,3
# # OEIS-Other: A000027 planepath=CellularRule,rule=2 coordinate_type=Y
# # OEIS-Other: A000027 planepath=CellularRule,rule=4 coordinate_type=Sum
# # OEIS-Other: A000027 planepath=CellularRule,rule=4 coordinate_type=DiffYX
# # OEIS-Other: A000027 planepath=CellularRule,rule=4 coordinate_type=AbsDiff
# # OEIS-Other: A000027 planepath=CellularRule,rule=4 coordinate_type=Radius
# }
}
{ package Math::PlanePath::CellularRule::OddSolid;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
use constant _NumSeq_Coord_Parity_max => 0; # always even points
}
{ package Math::PlanePath::CellularRule54;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
use constant _NumSeq_Coord_IntXY_min => -1;
}
{ package Math::PlanePath::CellularRule57;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
use constant _NumSeq_Coord_IntXY_min => -1;
}
{ package Math::PlanePath::CellularRule190;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
use constant _NumSeq_Coord_IntXY_min => -1;
}
{ package Math::PlanePath::UlamWarburton;
use constant _NumSeq_Coord_LeafDistance_max => 4;
}
{ package Math::PlanePath::UlamWarburtonQuarter;
use constant _NumSeq_Coord_LeafDistance_max => 4;
use constant _NumSeq_Coord_Parity_max => 0; # even always
}
{ package Math::PlanePath::DiagonalRationals;
use constant _NumSeq_Coord_Sum_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_SumAbs_non_decreasing => 1; # X+Y diagonals
use constant _NumSeq_Coord_BitAnd_min => 0; # at X=1,Y=2
use constant _NumSeq_Coord_oeis_anum =>
{ 'direction=down,n_start=1' =>
{ X => 'A020652', # numerators
Y => 'A020653', # denominators
Numerator => 'A020652', # Numerator=X
Denominator => 'A020653', # Denominator=Y
# OEIS-Catalogue: A020652 planepath=DiagonalRationals coordinate_type=X
# OEIS-Catalogue: A020653 planepath=DiagonalRationals coordinate_type=Y
# OEIS-Other: A020652 planepath=DiagonalRationals coordinate_type=Numerator
# OEIS-Other: A020653 planepath=DiagonalRationals coordinate_type=Denominator
# Not quite, A038567 has OFFSET=0 to include 0/1
# Sum => 'A038567', # num+den, is den of fractions X/Y <= 1
# SumAbs => 'A038567'
},
'direction=down,n_start=0' =>
{ AbsDiff => 'A157806', # abs(num-den), OFFSET=0
# OEIS-Other: A157806 planepath=DiagonalRationals,n_start=0 coordinate_type=AbsDiff
},
'direction=up,n_start=1' =>
{ X => 'A020653', # transposed is denominators
Y => 'A020652', # transposed is numerators
Numerator => 'A020653', # Numerator=X
Denominator => 'A020652', # Denominator=Y
# OEIS-Other: A020652 planepath=DiagonalRationals,direction=up coordinate_type=Y
# OEIS-Other: A020653 planepath=DiagonalRationals,direction=up coordinate_type=X
# OEIS-Other: A020653 planepath=DiagonalRationals,direction=up coordinate_type=Numerator
# OEIS-Other: A020652 planepath=DiagonalRationals,direction=up coordinate_type=Denominator
# Not quite, A038567 has OFFSET=0 to include 0/1
# Sum => 'A038567', # num+den, is den of fractions X/Y <= 1
},
'direction=up,n_start=0' =>
{ AbsDiff => 'A157806', # abs(num-den), OFFSET=0
# OEIS-Other: A157806 planepath=DiagonalRationals,direction=up,n_start=0 coordinate_type=AbsDiff
},
};
}
{ package Math::PlanePath::FactorRationals;
use constant _NumSeq_Coord_BitAnd_min => 0; # at X=1,Y=2
use constant _NumSeq_Coord_oeis_anum =>
{ 'factor_coding=even/odd' =>
{ X => 'A071974', # numerators
Y => 'A071975', # denominators
Product => 'A019554', # replace squares by their root
# OEIS-Catalogue: A071974 planepath=FactorRationals coordinate_type=X
# OEIS-Catalogue: A071975 planepath=FactorRationals coordinate_type=Y
# OEIS-Catalogue: A019554 planepath=FactorRationals coordinate_type=Product
},
'factor_coding=odd/even' =>
{ X => 'A071975', # denominators
Y => 'A071974', # numerators
Product => 'A019554', # replace squares by their root
# OEIS-Other: A071975 planepath=FactorRationals,factor_coding=odd/even coordinate_type=X
# OEIS-Other: A071974 planepath=FactorRationals,factor_coding=odd/even coordinate_type=Y
# OEIS-Other: A019554 planepath=FactorRationals,factor_coding=odd/even coordinate_type=Product
},
};
}
{ package Math::PlanePath::GcdRationals;
use constant _NumSeq_Coord_BitAnd_min => 0; # at X=1,Y=2
use constant _NumSeq_Coord_oeis_anum =>
{ 'pairs_order=rows' =>
{ X => 'A226314',
Y => 'A054531', # T(n,k) = n/GCD(n,k), being denominators
# OEIS-Catalogue: A226314 planepath=GcdRationals coordinate_type=X
# OEIS-Catalogue: A054531 planepath=GcdRationals coordinate_type=Y
},
'pairs_order=rows_reverse' =>
{ Y => 'A054531', # same
# OEIS-Other: A054531 planepath=GcdRationals,pairs_order=rows coordinate_type=Y
},
};
}
{ package Math::PlanePath::CoprimeColumns;
use constant _NumSeq_Coord_X_non_decreasing => 1; # columns across
use constant _NumSeq_Coord_Numerator_non_decreasing => 1; # Numerator==X
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max==X
use constant _NumSeq_Coord_IntXY_min => 1; # octant Y<=X so X/Y>=1
use constant _NumSeq_Coord_BitAnd_min => 0; # at X=2,Y=1
use constant _NumSeq_Coord_oeis_anum =>
{ 'n_start=0' =>
{ X => 'A038567', # fractions denominator
Max => 'A038567', # Max=X since Y <= X
MaxAbs => 'A038567', # MaxAbs=Max
# OEIS-Catalogue: A038567 planepath=CoprimeColumns coordinate_type=X
# OEIS-Other: A038567 planepath=CoprimeColumns coordinate_type=Max
# OEIS-Other: A038567 planepath=CoprimeColumns coordinate_type=MaxAbs
},
'n_start=0,i_start=1' =>
{ DiffXY => 'A020653', # diagonals denominators, starting N=1
# OEIS-Other: A020653 planepath=CoprimeColumns coordinate_type=DiffXY i_start=1
},
'n_start=1' =>
{ Y => 'A038566', # fractions numerator
Min => 'A038566', # Min=Y since Y <= X
MinAbs => 'A038566', # MinAbs=Min
# OEIS-Catalogue: A038566 planepath=CoprimeColumns,n_start=1 coordinate_type=Y
# OEIS-Other: A038566 planepath=CoprimeColumns,n_start=1 coordinate_type=Min
# OEIS-Other: A038566 planepath=CoprimeColumns,n_start=1 coordinate_type=MinAbs
},
};
}
{ package Math::PlanePath::DivisibleColumns;
use constant _NumSeq_Coord_X_non_decreasing => 1; # columns across
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return ($self->{'proper'} ? 2 : 1);
}
use constant _NumSeq_Coord_FracXY_max => 0; # frac(X/Y)=0 always
use constant _NumSeq_Coord_FracXY_integer => 1;
use constant _NumSeq_FracXY_max_is_supremum => 0;
sub _NumSeq_Coord_Numerator_min {
my ($self) = @_;
return ($self->{'proper'} ? 2 : 1);
}
# X/Y = Z/1 since X divisible by Y, Denominator=1 always
use constant _NumSeq_Coord_Denominator_min => 1;
use constant _NumSeq_Coord_Denominator_max => 1;
use constant _NumSeq_Coord_Denominator_non_decreasing => 1;
use constant _NumSeq_Coord_BitAnd_min => 0; # at X=2,Y=1
sub _NumSeq_Coord_BitXor_min {
my ($self) = @_;
# octant Y<=X so X-Y>=0
return ($self->{'proper'} ? 2 # at X=3,Y=1
: 0); # at X=1,Y=1
}
use constant _NumSeq_Coord_Max_non_decreasing => 1; # Max==X
sub _NumSeq_Coord_MaxAbs_min { return $_[0]->x_minimum } # Max=X
use constant _NumSeq_Coord_HammingDist_min => 1; # X!=Y
use constant _NumSeq_Coord_oeis_anum =>
{ 'divisor_type=all,n_start=1' =>
{ X => 'A061017', # n appears divisors(n) times
Max => 'A061017', # Max=X since Y <= X
MaxAbs => 'A061017', # MaxAbs=Max
Y => 'A027750', # triangle divisors of n
Min => 'A027750', # Min=Y since Y <= X
MinAbs => 'A027750', # MinAbs=Min
GCD => 'A027750', # Y since Y is a divisor of X
IntXY => 'A056538', # divisors in reverse order, X/Y give high to low
Numerator => 'A056538', # same as int(X/Y)
# OEIS-Catalogue: A061017 planepath=DivisibleColumns,n_start=1 coordinate_type=X
# OEIS-Other: A061017 planepath=DivisibleColumns,n_start=1 coordinate_type=Max
# OEIS-Other: A061017 planepath=DivisibleColumns,n_start=1 coordinate_type=MaxAbs
# OEIS-Catalogue: A027750 planepath=DivisibleColumns,n_start=1 coordinate_type=Y
# OEIS-Other: A027750 planepath=DivisibleColumns,n_start=1 coordinate_type=Min
# OEIS-Other: A027750 planepath=DivisibleColumns,n_start=1 coordinate_type=GCD
# OEIS-Catalogue: A056538 planepath=DivisibleColumns,n_start=1 coordinate_type=IntXY
# OEIS-Other: A056538 planepath=DivisibleColumns,n_start=1 coordinate_type=Numerator
},
'divisor_type=proper,n_start=2' =>
{ DiffXY => 'A208460', # X-Y
AbsDiff => 'A208460', # abs(X-Y) same since Y<=X so X-Y>=0
# OEIS-Catalogue: A208460 planepath=DivisibleColumns,divisor_type=proper,n_start=2 coordinate_type=DiffXY
# OEIS-Other: A208460 planepath=DivisibleColumns,divisor_type=proper,n_start=2 coordinate_type=AbsDiff
# Not quite, A027751 has an extra 1 at the start from reckoning by
# convention 1 as a proper divisor of 1 -- though that's
# inconsistent with A032741 count of proper divisors being 0.
#
# 'divisor_type=proper,n_start=0' =>
# { Y,Min,GCD => 'A027751', # proper divisors by rows
# # OEIS-Catalogue: A027751 planepath=DivisibleColumns,divisor_type=proper coordinate_type=Y
# },
},
};
}
# { package Math::PlanePath::File;
# # File points from a disk file
# # FIXME: analyze points for min/max maybe
# }
# { package Math::PlanePath::QuintetCurve;
# # inherit from QuintetCentres
# }
# { package Math::PlanePath::QuintetCentres;
# }
# { package Math::PlanePath::QuintetReplicate;
# }
# { package Math::PlanePath::AR2W2Curve;
# }
# { package Math::PlanePath::BetaOmega;
# }
# { package Math::PlanePath::KochelCurve;
# }
# { package Math::PlanePath::DekkingCurve;
# }
# { package Math::PlanePath::DekkingCentres;
# }
# { package Math::PlanePath::CincoCurve;
# }
# { package Math::PlanePath::SquareReplicate;
# }
{ package Math::PlanePath::CornerReplicate;
use constant _NumSeq_Coord_oeis_anum =>
{ '' =>
{ Y => 'A059906', # alternate bits second (ZOrderCurve Y)
BitXor => 'A059905', # alternate bits first (ZOrderCurve X)
HammingDist => 'A139351', # count 1-bits at even bit positions
# OEIS-Other: A059906 planepath=CornerReplicate coordinate_type=Y
# OEIS-Other: A059905 planepath=CornerReplicate coordinate_type=BitXor
# OEIS-Catalogue: A139351 planepath=CornerReplicate coordinate_type=HammingDist
},
};
}
# { package Math::PlanePath::DigitGroups;
# # Not quite, A073089 is OFFSET=1 not N=0, also A073089 has extra initial 0
# # use constant _NumSeq_Coord_oeis_anum =>
# # { 'radix=2' =>
# # { Parity => 'A073089', # DragonMidpoint AbsdY Nodd ^ bit-above-low-0
# # # OEIS-Other: A073089 planepath=DigitGroups coordinate_type=Parity
# # },
# # };
# }
# { package Math::PlanePath::FibonacciWordFractal;
# }
{ package Math::PlanePath::LTiling;
# X=1,Y=1 doesn't occur, only X=1,Y=2 or X=2,Y=1
{
my %_NumSeq_Coord_Max_min = (upper => 1, # X=0,Y=0 not visited by these
left => 1,
ends => 1);
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
return $_NumSeq_Coord_Max_min{$self->{'L_fill'}} || 0;
}
}
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
return ($self->{'L_fill'} eq 'upper' ? 3 # X=0,Y=1
: ($self->{'L_fill'} eq 'left'
|| $self->{'L_fill'} eq 'ends') ? 1 # X=1,Y=0
: 0); # 'middle','all' X=0,Y=0
}
{
my %BitOr_min = (upper => 1, # X=0,Y=0 not visited by these
left => 1,
ends => 1);
sub _NumSeq_Coord_BitOr_min {
my ($self) = @_;
return $BitOr_min{$self->{'L_fill'}} || 0;
}
}
*_NumSeq_Coord_BitXor_min = \&_NumSeq_Coord_BitOr_min;
{
my %_NumSeq_Coord_HammingDist_min = (upper => 1, # X!=Y for these
left => 1,
ends => 1);
sub _NumSeq_Coord_HammingDist_min {
my ($self) = @_;
return $_NumSeq_Coord_HammingDist_min{$self->{'L_fill'}} || 0;
}
*_NumSeq_Coord_MaxAbs_min = \&_NumSeq_Coord_HammingDist_min;
}
# Not quite, A112539 OFFSET=1 versus start N=0 here
# use constant _NumSeq_Coord_oeis_anum =>
# { 'L_fill=left' =>
# { Parity => 'A112539', # thue-morse count1bits mod 2
# # OEIS-Catalogue: A112539 planepath=LTiling,L_fill=left coordinate_type=Parity
# },
# };
}
{ package Math::PlanePath::WythoffArray;
# FIXME: if x_start=1 but y_start=0 then want corresponding mixture of
# A-nums. DiffXY is whenever x_start==y_start.
use constant _NumSeq_Coord_oeis_anum =>
{ 'x_start=0,y_start=0' =>
{ Y => 'A019586', # row containing N
DiffXY => 'A191360', # diagonal containing N
# OEIS-Catalogue: A019586 planepath=WythoffArray coordinate_type=Y
# OEIS-Catalogue: A191360 planepath=WythoffArray coordinate_type=DiffXY
# Not quite, A035614 has OFFSET start n=0 whereas path starts N=1
# X => 'A035614',
},
'x_start=1,y_start=1' =>
{ X => 'A035612', # column number containing N, start column=1
Y => 'A003603', # row number containing N, starting row=1
DiffXY => 'A191360', # diagonal containing N
# OEIS-Catalogue: A035612 planepath=WythoffArray,x_start=1,y_start=1
# OEIS-Catalogue: A003603 planepath=WythoffArray,x_start=1,y_start=1 coordinate_type=Y
# OEIS-Other: A191360 planepath=WythoffArray,x_start=1,y_start=1 coordinate_type=DiffXY
},
};
}
{ package Math::PlanePath::PowerArray;
use constant _NumSeq_Coord_oeis_anum =>
{ 'radix=2' =>
{ X => 'A007814', # base 2 count low 0s, starting n=1
# main generator Math::NumSeq::DigitCountLow
# OEIS-Other: A007814 planepath=PowerArray,radix=2
# Not quite, A025480 starts OFFSET=0 for the k in n=(2k+1)*2^j-1
# Y => 'A025480',
# # OEIS-Almost: A025480 i_to_n_offset=-1 planepath=PowerArray,radix=2 coordinate_type=Y
},
'radix=3' =>
{ X => 'A007949', # k of greatest 3^k dividing n
# OEIS-Other: A007949 planepath=PowerArray,radix=3
# main generator Math::NumSeq::DigitCountLow
},
'radix=5' =>
{ X => 'A112765',
# OEIS-Other: A112765 planepath=PowerArray,radix=5
},
'radix=6' =>
{ X => 'A122841',
# OEIS-Other: A122841 planepath=PowerArray,radix=6
},
'radix=10' =>
{ X => 'A122840',
# OEIS-Other: A112765 planepath=PowerArray,radix=5
},
};
}
{ package Math::PlanePath::ToothpickTree;
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
if ($self->{'parts'} eq '3') { return 0; }
return $self->SUPER::_NumSeq_Coord_Max_min;
}
{
my %_NumSeq_Coord_IntXY_min = (1 => 0,
octant => 0, # X>=Y-1 so X/Y >= 1-1/Y
wedge => -1, # X>=-Y,Y>=0 so X/Y<=-1
);
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_min{$self->{'parts'}};
}
}
{
my %_NumSeq_Coord_IntXY_max = (octant_up => 0,
# except wedge 0/0 = infinity
# wedge => 1, # Y>=X so X/Y<=1
);
sub _NumSeq_Coord_IntXY_max {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_max{$self->{'parts'}};
}
}
sub _NumSeq_Coord_BitAnd_min {
my ($self) = @_;
return ($self->{'parts'} eq '4'
? undef # X<0,Y<0
: 0); # otherwise X>0 or Y>0 so BitAnd>=0
}
{
my %_NumSeq_Coord_TRSquared_min = (2 => 3, # X=0,Y=1
1 => 4, # X=1,Y=1
octant => 4, # X=1,Y=1
octant_up => 13, # X=1,Y=2
);
sub _NumSeq_Coord_TRSquared_min {
my ($self) = @_;
return ($_NumSeq_Coord_TRSquared_min{$self->{'parts'}} || 0);
}
}
{
# usually 7, but in these 8
my %_NumSeq_Coord_LeafDistance_max = (octant => 8,
octant_up => 8,
wedge => 8,
);
sub _NumSeq_Coord_LeafDistance_max {
my ($self) = @_;
return ($_NumSeq_Coord_LeafDistance_max{$self->{'parts'}} || 7);
}
}
}
{ package Math::PlanePath::ToothpickReplicate;
*_NumSeq_Coord_BitAnd_min
= \&Math::PlanePath::ToothpickTree::_NumSeq_Coord_BitAnd_min;
*_NumSeq_Coord_TRSquared_min
= \&Math::PlanePath::ToothpickTree::_NumSeq_Coord_TRSquared_min;
}
{ package Math::PlanePath::ToothpickUpist;
use constant _NumSeq_Coord_Y_non_decreasing => 1; # rows upwards
use constant _NumSeq_Coord_Max_non_decreasing => 1; # X<=Y so max=Y
use constant _NumSeq_Coord_MaxAbs_non_decreasing => 1; # -Y<=X<=Y so MaxAbs=Y
use constant _NumSeq_Coord_LeafDistance_max => 9;
}
{ package Math::PlanePath::LCornerTree;
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
return ($self->{'parts'} eq '4' ? undef : 0);
}
{
my %_NumSeq_Coord_IntXY_min
= (1 => 0,
octant => 1, # X>=Y so X/Y>=1, and 0/0
'octant+1' => 0, # X>=Y-1 so int(X/Y)>=0
octant_up => 0, # X>=0 so X/Y>=1, and 0/0
'octant_up+1' => 0, # X>=0 so X/Y>=1, and 0/0
wedge => -2, # X>=-Y-1 so X/Y>=-2
'wedge+1' => -3, # X>=-Y-2 so X/Y>=-3
);
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
return $_NumSeq_Coord_IntXY_min{$self->{'parts'}};
}
}
use constant _NumSeq_Coord_LeafDistance_max => 2;
}
# { package Math::PlanePath::LCornerReplicate;
# }
# { package Math::PlanePath::PeninsulaBridge;
# }
{ package Math::PlanePath::OneOfEight;
sub _NumSeq_Coord_Max_min {
my ($self) = @_;
return ($self->{'parts'} eq '4' ? undef : 0);
}
sub _NumSeq_Coord_IntXY_min {
my ($self) = @_;
if ($self->{'parts'} eq 'octant') { return 1; }
return $self->SUPER::_NumSeq_Coord_IntXY_min;
}
{
# usually 2, but in 3side only 1
my %_NumSeq_Coord_LeafDistance_max = ('3side' => 1,
);
sub _NumSeq_Coord_LeafDistance_max {
my ($self) = @_;
return $_NumSeq_Coord_LeafDistance_max{$self->{'parts'}} || 2;
}
}
}
{ package Math::PlanePath::HTree;
use constant _NumSeq_Coord_Depth_non_decreasing => 0;
use constant _NumSeq_Coord_NumSiblings_non_decreasing => 1;
}
#------------------------------------------------------------------------------
1;
__END__
# sub pred {
# my ($self, $value) = @_;
#
# my $planepath_object = $self->{'planepath_object'};
# my $figure = $planepath_object->figure;
# if ($figure eq 'square') {
# if ($value != int($value)) {
# return 0;
# }
# } elsif ($figure eq 'circle') {
# return 1;
# }
#
# my $coordinate_type = $self->{'coordinate_type'};
# if ($coordinate_type eq 'X') {
# if ($planepath_object->x_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# } elsif ($coordinate_type eq 'Y') {
# if ($planepath_object->y_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# } elsif ($coordinate_type eq 'Sum') {
# if ($planepath_object->x_negative || $planepath_object->y_negative) {
# return 1;
# } else {
# return ($value >= 0);
# }
# } elsif ($coordinate_type eq 'RSquared') {
# # FIXME: only sum of two squares, and for triangular same odd/even.
# # Factorize or search ?
# return ($value >= 0);
# }
#
# return undef;
# }
=for stopwords Ryde Math-PlanePath PlanePath DiffXY AbsDiff IntXY FracXY OEIS NumSeq SquareSpiral SumAbs Manhatten ie TRadius TRSquared RSquared DiffYX BitAnd BitOr BitXor bitand bitwise
=head1 NAME
Math::NumSeq::PlanePathCoord -- sequence of coordinate values from a PlanePath module
=head1 SYNOPSIS
use Math::NumSeq::PlanePathCoord;
my $seq = Math::NumSeq::PlanePathCoord->new
(planepath => 'SquareSpiral',
coordinate_type => 'X');
my ($i, $value) = $seq->next;
=head1 DESCRIPTION
This is a tie-in to make a C sequence giving coordinate values from
a C. The NumSeq "i" index is the PlanePath "N" value.
The C choices are as follows. Generally they have some
sort of geometric interpretation or are related to fractions X/Y.
"X" X coordinate
"Y" Y coordinate
"Min" min(X,Y)
"Max" max(X,Y)
"MinAbs" min(abs(X),abs(Y))
"MaxAbs" max(abs(X),abs(Y))
"Sum" X+Y sum
"SumAbs" abs(X)+abs(Y) sum
"Product" X*Y product
"DiffXY" X-Y difference
"DiffYX" Y-X difference (negative of DiffXY)
"AbsDiff" abs(X-Y) difference
"Radius" sqrt(X^2+Y^2) radial distance
"RSquared" X^2+Y^2 radius squared
"TRadius" sqrt(X^2+3*Y^2) triangular radius
"TRSquared" X^2+3*Y^2 triangular radius squared
"IntXY" int(X/Y) division rounded towards zero
"FracXY" frac(X/Y) division rounded towards zero
"BitAnd" X bitand Y
"BitOr" X bitor Y
"BitXor" X bitxor Y
"GCD" greatest common divisor X,Y
"Depth" tree_n_to_depth()
"SubHeight" tree_n_to_subheight()
"NumChildren" tree_n_num_children()
"NumSiblings" not including self
"RootN" the N which is the tree root
"IsLeaf" 0 or 1 whether a leaf node (no children)
"IsNonLeaf" 0 or 1 whether a non-leaf node (has children)
also called an "internal" node
=head2 Min and Max
"Min" and "Max" are the minimum or maximum of X and Y. The geometric
interpretation of "Min" is to select X at any point above the X=Y diagonal
or Y for any point below. Conversely "Max" is Y above and X below. On the
X=Y diagonal itself X=Y=Min=Max.
Max=Y / X=Y diagonal
Min=X | /
|/
---o----
/|
/ | Max=X
/ Min=Y
XMin and Max can also be interpreted as counting which gnomon shaped
line the X,Y falls on.
| | | | Min=gnomon 2 ------------. Max=gnomon
| | | | 1 ----------. |
| | | | ... 0 --------o | |
| | | ------ 1 -1 ------. | | |
| | o-------- 0 ... | | | |
| ---------- -1 | | | |
------------ -2 | | | |
=head2 MinAbs
XMinAbs = min(abs(X),abs(Y)) can be interpreted geometrically as
counting gnomons successively away from the origin. This is like Min above,
but within the quadrant containing X,Y.
| | | | | MinAbs=gnomon counted away from the origin
| | | | |
2 --- | | | ---- 2
1 ----- | ------ 1
0 -------o-------- 0
1 ----- | ------ 1
2 --- | | | ---- 2
| | | | |
| | | | |
=head2 MaxAbs
MaxAbs = max(abs(X),abs(Y)) can be interpreted geometrically as counting
successive squares around the origin.
+-----------+ MaxAbs=which square
| +-------+ |
| | +---+ | |
| | | o | | |
| | +---+ | |
| +-------+ |
+-----------+
For example L loops around in squares and so
its MaxAbs is unchanged until it steps out to the next bigger square.
=head2 Sum and Diff
"Sum"=X+Y and "DiffXY"=X-Y can be interpreted geometrically as coordinates
on 45-degree diagonals. Sum is a measure up along the leading diagonal and
DiffXY down an anti-diagonal,
\ /
\ s=X+Y /
\ ^\
\ / \
\ | / v
\|/ * d=X-Y
---o----
/|\
/ | \
/ | \
/ \
/ \
/ \
Or "Sum" can be thought of as a count of which anti-diagonal stripe contains
X,Y, or a projection onto the X=Y leading diagonal.
Sum
\ = anti-diag
2 numbering / / / / DiffXY
\ \ X+Y -1 0 1 2 = diagonal
1 2 / / / / numbering
\ \ \ -1 0 1 2 X-Y
0 1 2 / / /
\ \ \ 0 1 2
=head2 DiffYX
"DiffYX" = Y-X is simply the negative of DiffXY. It's included to give
positive values on paths which are above the X=Y leading diagonal. For
example DiffXY is positive in C which is below X=Y, whereas
DiffYX is positive in C which is above X=Y.
=head2 SumAbs
X"SumAbs" = abs(X)+abs(Y) is similar to the projection described above for
Sum or Diff, but SumAbs projects onto the central diagonal of whichever
quadrant contains the X,Y. Or equivalently it's a numbering of
anti-diagonals within that quadrant, so numbering which diamond shape the
X,Y falls on.
|
/|\ SumAbs = which diamond X,Y falls on
/ | \
/ | \
-----o-----
\ | /
\ | /
\|/
|
As an example, the C path loops around on such diamonds, so
its SumAbs is unchanged until completing a loop and stepping out to the next
bigger.
XXSumAbs is also a "taxi-cab" or "Manhatten" distance,
being how far to travel through a square-grid city to get to X,Y.
SumAbs = taxi-cab distance, by any square-grid travel
+-----o +--o o
| | |
| +--+ +-----+
| | |
* * *
If a path is entirely XE=0,YE=0 in the first quadrant then Sum and
SumAbs are identical.
=head2 AbsDiff
"AbsDiff" = abs(X-Y) can be interpreted geometrically as the distance away
from the X=Y diagonal, measured at right-angles to that line.
d=abs(X-Y)
^ / X=Y line
\ /
\/
/\
/ \
|/ \
--o-- \
/| v
/ d=abs(X-Y)
If a path is entirely below the X=Y line, so XE=Y, then AbsDiff is the
same as DiffXY. Or if a path is entirely above the X=Y line, so YE=X,
then AbsDiff is the same as DiffYX.
=head2 Radius and RSquared
Radius and RSquared are per C<$path-En_to_radius()> and
C<$path-En_to_rsquared()> respectively (see L).
=head2 TRadius and TRSquared
"TRadius" and "TRSquared" are designed for use with points on a triangular
lattice as per L. For points on the X
axis TRSquared is the same as RSquared but off the axis Y is scaled up by
factor sqrt(3).
Most triangular paths use "even" points X==Y mod 2 and for them TRSquared is
always even. Some triangular paths such as C have an offset from
the origin and use "odd" points X!=Y mod 2 and for them TRSquared is odd.
=head2 IntXY and FracXY
"IntXY" = int(X/Y) is the quotient from X divide Y rounded to an integer
towards zero. This is like the integer part of a fraction, for example
X=9,Y=4 is 9/4 = 2+1/4 so IntXY=2. Negatives are reckoned with the fraction
part negated too, so -2 1/4 is -2-1/4 and thus IntXY=-2.
Geometrically IntXY gives which wedge of slope 1, 2, 3, etc the point X,Y
falls in. For example IntXY is 3 for all points in the wedge
3YE=XE4Y.
X=Y X=2Y X=3Y X=4Y
* -2 * -1 * 0 | 0 * 1 * 2 * 3 *
* * * | * * * *
* * * | * * * *
* * * | * * * *
* * * | * * * *
* * * | * * * *
***|****
---------------------+----------------------------
**|**
* * | * *
* * | * *
* * | * *
* * | * *
2 * 1 * 0 | 0 * -1 * -2
"FracXY" is the fraction part which goes with IntXY. In all cases
X/Y = IntXY + FracXY
IntXY rounds towards zero so the remaining FracXY has the same sign as
IntXY.
=head2 BitAnd, BitOr, BitXor
"BitAnd", "BitOr" and "BitXor" treat negative X or negative Y as infinite
twos-complement 1-bits, which means for example X=-1,Y=-2 has X bitand Y
= -2.
...11111111 X=-1
...11111110 Y=-2
-----------
...11111110 X bitand Y = -2
This twos-complement is per C (which has bitwise operations in
Perl 5.6 and up). The code here arranges the same on ordinary scalars.
If X or Y are not integers then the fractional parts are treated bitwise
too, but currently only to limited precision.
=head1 FUNCTIONS
See L for behaviour common to all sequence classes.
=over 4
=item C<$seq = Math::NumSeq::PlanePathCoord-Enew (planepath =E $name, coordinate_type =E $str)>
Create and return a new sequence object. The options are
planepath string, name of a PlanePath module
planepath_object PlanePath object
coordinate_type string, as described above
C can be either the module part such as "SquareSpiral" or a
full class name "Math::PlanePath::SquareSpiral".
=item C<$value = $seq-Eith($i)>
Return the coordinate at N=$i in the PlanePath.
=item C<$i = $seq-Ei_start()>
Return the first index C<$i> in the sequence. This is the position
C returns to.
This is C<$path-En_start()> from the PlanePath, since the i numbering is
the N numbering of the underlying path. For some of the
C generated sequences there may be a higher C
corresponding to a higher starting point in the OEIS, though this is
slightly experimental.
=item C<$str = $seq-Eoeis_anum()>
Return the A-number (a string) for C<$seq> in Sloane's Online Encyclopedia
of Integer Sequences, or return C if not in the OEIS or not known.
Known A-numbers are also presented through C.
This means PlanePath related OEIS sequences can be created with
C by giving their A-number in the usual way for that
module.
=back
=head1 SEE ALSO
L,
L,
L,
L,
L
L
=head1 HOME PAGE
L
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/lib/Math/NumSeq/OEIS/ 0002755 0001750 0001750 00000000000 12255673733 015324 5 ustar gg gg Math-PlanePath-113/lib/Math/NumSeq/OEIS/Catalogue/ 0002755 0001750 0001750 00000000000 12255673733 017230 5 ustar gg gg Math-PlanePath-113/lib/Math/NumSeq/OEIS/Catalogue/Plugin/ 0002755 0001750 0001750 00000000000 12255673733 020466 5 ustar gg gg Math-PlanePath-113/lib/Math/NumSeq/OEIS/Catalogue/Plugin/PlanePath.pm 0000644 0001750 0001750 00000133715 12255673732 022707 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# Generated by Math-NumSeq tools/make-oeis-catalogue.pl -- DO NOT EDIT
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
package Math::NumSeq::OEIS::Catalogue::Plugin::PlanePath;
use 5.004;
use strict;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::NumSeq::OEIS::Catalogue::Plugin;
@ISA = ('Math::NumSeq::OEIS::Catalogue::Plugin');
## no critic (CodeLayout::RequireTrailingCommaAtNewline)
# total 242 A-numbers in 4 modules
use constant info_arrayref =>
[
{
'anum' => 'A174344',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'SquareSpiral',
'coordinate_type',
'X'
]
},
{
'anum' => 'A214526',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'SquareSpiral',
'coordinate_type',
'SumAbs'
]
},
{
'anum' => 'A180714',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'SquareSpiral,n_start=0',
'coordinate_type',
'Sum'
]
},
{
'anum' => 'A053615',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidSpiral,n_start=0',
'coordinate_type',
'AbsX'
]
},
{
'anum' => 'A010751',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiamondSpiral,n_start=0'
]
},
{
'anum' => 'A153036',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree',
'coordinate_type',
'IntXY'
]
},
{
'anum' => 'A000523',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree',
'coordinate_type',
'Depth'
]
},
{
'anum' => 'A070871',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=CW',
'coordinate_type',
'Product'
]
},
{
'anum' => 'A020650',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=AYT',
'coordinate_type',
'X'
]
},
{
'anum' => 'A020651',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=AYT',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A135523',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=AYT',
'coordinate_type',
'IntXY'
]
},
{
'anum' => 'A162909',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Bird',
'coordinate_type',
'X'
]
},
{
'anum' => 'A162910',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Bird',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A162911',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Drib',
'coordinate_type',
'X'
]
},
{
'anum' => 'A162912',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Drib',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A174981',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'RationalsTree,tree_type=L',
'coordinate_type',
'X'
]
},
{
'anum' => 'A086592',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'FractionsTree',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A191379',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ChanTree'
]
},
{
'anum' => 'A163528',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PeanoCurve',
'coordinate_type',
'X'
]
},
{
'anum' => 'A163529',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PeanoCurve',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A163530',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PeanoCurve',
'coordinate_type',
'Sum'
]
},
{
'anum' => 'A163531',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PeanoCurve',
'coordinate_type',
'RSquared'
]
},
{
'anum' => 'A059253',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'HilbertCurve',
'coordinate_type',
'X'
]
},
{
'anum' => 'A059252',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'HilbertCurve',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A059261',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'HilbertCurve',
'coordinate_type',
'Sum'
]
},
{
'anum' => 'A059285',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'HilbertCurve',
'coordinate_type',
'DiffXY'
]
},
{
'anum' => 'A163547',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'HilbertCurve',
'coordinate_type',
'RSquared'
]
},
{
'anum' => 'A059905',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve',
'coordinate_type',
'X'
]
},
{
'anum' => 'A059906',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A163325',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve,radix=3',
'coordinate_type',
'X'
]
},
{
'anum' => 'A163326',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve,radix=3',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A080463',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve,radix=10',
'coordinate_type',
'Sum',
'i_start',
1
]
},
{
'anum' => 'A080464',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve,radix=10',
'coordinate_type',
'Product',
'i_start',
10
]
},
{
'anum' => 'A080465',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'ZOrderCurve,radix=10',
'coordinate_type',
'AbsDiff',
'i_start',
10
]
},
{
'anum' => 'A164306',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=0',
'coordinate_type',
'Numerator'
]
},
{
'anum' => 'A167192',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=0',
'coordinate_type',
'Denominator'
]
},
{
'anum' => 'A004247',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'Product'
]
},
{
'anum' => 'A114327',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'DiffYX'
]
},
{
'anum' => 'A049581',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'AbsDiff'
]
},
{
'anum' => 'A048147',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'RSquared'
]
},
{
'anum' => 'A004198',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'BitAnd'
]
},
{
'anum' => 'A003986',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'BitOr'
]
},
{
'anum' => 'A003987',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'BitXor'
]
},
{
'anum' => 'A109004',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'GCD'
]
},
{
'anum' => 'A004197',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'Min'
]
},
{
'anum' => 'A003984',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'Max'
]
},
{
'anum' => 'A101080',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'coordinate_type',
'HammingDist'
]
},
{
'anum' => 'A003991',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=1',
'coordinate_type',
'Product'
]
},
{
'anum' => 'A003989',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=1',
'coordinate_type',
'GCD'
]
},
{
'anum' => 'A003983',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=1',
'coordinate_type',
'Min'
]
},
{
'anum' => 'A051125',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=1',
'coordinate_type',
'Max'
]
},
{
'anum' => 'A004199',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,x_start=1,y_start=1',
'coordinate_type',
'IntXY'
]
},
{
'anum' => 'A003988',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,direction=up,x_start=1,y_start=1',
'coordinate_type',
'IntXY'
]
},
{
'anum' => 'A112543',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,direction=up,x_start=1,y_start=1',
'coordinate_type',
'Numerator'
]
},
{
'anum' => 'A112544',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Diagonals,direction=up,x_start=1,y_start=1',
'coordinate_type',
'Denominator'
]
},
{
'anum' => 'A055087',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiagonalsOctant,n_start=0',
'coordinate_type',
'X'
]
},
{
'anum' => 'A055086',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiagonalsOctant,n_start=0',
'coordinate_type',
'Sum'
]
},
{
'anum' => 'A082375',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiagonalsOctant,n_start=0',
'coordinate_type',
'DiffYX'
]
},
{
'anum' => 'A213088',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'Corner',
'coordinate_type',
'Sum'
]
},
{
'anum' => 'A079904',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'coordinate_type',
'Product'
]
},
{
'anum' => 'A069011',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'coordinate_type',
'RSquared'
]
},
{
'anum' => 'A080099',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'coordinate_type',
'BitAnd'
]
},
{
'anum' => 'A080098',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'coordinate_type',
'BitOr'
]
},
{
'anum' => 'A051933',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'coordinate_type',
'BitXor'
]
},
{
'anum' => 'A196199',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,n_start=0',
'coordinate_type',
'X'
]
},
{
'anum' => 'A000196',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,n_start=0',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A180447',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=3,n_start=0',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A060511',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'PyramidRows,step=4,align=right,n_start=0',
'coordinate_type',
'X'
]
},
{
'anum' => 'A004396',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CellularRule,rule=6,n_start=0',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A131452',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CellularRule,rule=6,n_start=0',
'coordinate_type',
'SumAbs'
]
},
{
'anum' => 'A004523',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CellularRule,rule=20,n_start=0',
'coordinate_type',
'X'
]
},
{
'anum' => 'A004773',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CellularRule,rule=20,n_start=0',
'coordinate_type',
'SumAbs'
]
},
{
'anum' => 'A020652',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiagonalRationals',
'coordinate_type',
'X'
]
},
{
'anum' => 'A020653',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DiagonalRationals',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A071974',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'FactorRationals',
'coordinate_type',
'X'
]
},
{
'anum' => 'A071975',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'FactorRationals',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A019554',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'FactorRationals',
'coordinate_type',
'Product'
]
},
{
'anum' => 'A226314',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'GcdRationals',
'coordinate_type',
'X'
]
},
{
'anum' => 'A054531',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'GcdRationals',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A038567',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CoprimeColumns',
'coordinate_type',
'X'
]
},
{
'anum' => 'A038566',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CoprimeColumns,n_start=1',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A061017',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DivisibleColumns,n_start=1',
'coordinate_type',
'X'
]
},
{
'anum' => 'A027750',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DivisibleColumns,n_start=1',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A056538',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DivisibleColumns,n_start=1',
'coordinate_type',
'IntXY'
]
},
{
'anum' => 'A208460',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'DivisibleColumns,divisor_type=proper,n_start=2',
'coordinate_type',
'DiffXY'
]
},
{
'anum' => 'A139351',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'CornerReplicate',
'coordinate_type',
'HammingDist'
]
},
{
'anum' => 'A019586',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'WythoffArray',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A191360',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'WythoffArray',
'coordinate_type',
'DiffXY'
]
},
{
'anum' => 'A035612',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'WythoffArray,x_start=1,y_start=1'
]
},
{
'anum' => 'A003603',
'class' => 'Math::NumSeq::PlanePathCoord',
'parameters' => [
'planepath',
'WythoffArray,x_start=1,y_start=1',
'coordinate_type',
'Y'
]
},
{
'anum' => 'A079813',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'SquareSpiral',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A204439',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'TriangleSpiralSkewed,skew=left',
'delta_type',
'AbsdX'
]
},
{
'anum' => 'A204437',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'TriangleSpiralSkewed,skew=left',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A204435',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'TriangleSpiralSkewed,skew=right',
'delta_type',
'AbsdX'
]
},
{
'anum' => 'A003982',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'DiamondSpiral,n_start=0',
'delta_type',
'dSumAbs'
]
},
{
'anum' => 'A023532',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'AztecDiamondRings,n_start=0',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A070990',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'RationalsTree,tree_type=L',
'delta_type',
'dY'
]
},
{
'anum' => 'A011655',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'KochCurve',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A166486',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'DragonRounded',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A152822',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'DragonRounded',
'delta_type',
'AbsdX'
]
},
{
'anum' => 'A010059',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CCurve',
'delta_type',
'AbsdX'
]
},
{
'anum' => 'A033999',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Rows,width=2,n_start=0',
'delta_type',
'dX'
]
},
{
'anum' => 'A124625',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Rows,width=2,n_start=0',
'delta_type',
'dRSquared'
]
},
{
'anum' => 'A010673',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Rows,width=2,n_start=0',
'delta_type',
'TDir6'
]
},
{
'anum' => 'A061347',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Rows,width=3',
'delta_type',
'dX'
]
},
{
'anum' => 'A131561',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Rows,width=3,n_start=0',
'delta_type',
'dSum'
]
},
{
'anum' => 'A127949',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Diagonals',
'delta_type',
'dY'
]
},
{
'anum' => 'A051340',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A023531',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'PyramidRows,step=1,n_start=0',
'delta_type',
'dY'
]
},
{
'anum' => 'A049240',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'PyramidSides',
'delta_type',
'AbsdY'
]
},
{
'anum' => 'A062157',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CellularRule,rule=14,n_start=0',
'delta_type',
'dSum'
]
},
{
'anum' => 'A109613',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CellularRule,rule=84,n_start=0',
'delta_type',
'dRSquared'
]
},
{
'anum' => 'A177702',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CellularRule,rule=20,n_start=0',
'delta_type',
'dSumAbs'
]
},
{
'anum' => 'A102283',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CellularRule,rule=6,n_start=0',
'delta_type',
'dSum'
]
},
{
'anum' => 'A131756',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'CellularRule,rule=6,n_start=0',
'delta_type',
'dSumAbs'
]
},
{
'anum' => 'A171587',
'class' => 'Math::NumSeq::PlanePathDelta',
'parameters' => [
'planepath',
'FibonacciWordFractal',
'delta_type',
'AbsdX'
]
},
{
'anum' => 'A054552',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral'
]
},
{
'anum' => 'A033951',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral',
'line_type',
'Y_neg'
]
},
{
'anum' => 'A053755',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A016754',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A033991',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A002939',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A002943',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A069894',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SquareSpiral,wider=1',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A185669',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidSpiral,n_start=2',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A062741',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiral,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A062708',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiral,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A062725',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiral,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A117625',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed'
]
},
{
'anum' => 'A006137',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'X_neg'
]
},
{
'anum' => 'A064225',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'Y_neg'
]
},
{
'anum' => 'A081589',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A038764',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A081267',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A081274',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A081266',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'TriangleSpiralSkewed,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A130883',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'DiamondSpiral'
]
},
{
'anum' => 'A058331',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'DiamondSpiral',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A192136',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed'
]
},
{
'anum' => 'A116668',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed',
'line_type',
'X_neg'
]
},
{
'anum' => 'A158187',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A005891',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A005476',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A005475',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed,n_start=0',
'line_type',
'X_neg'
]
},
{
'anum' => 'A028895',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PentSpiralSkewed,n_start=0',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A049450',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiral,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A028896',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiral,n_start=0',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A056105',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed'
]
},
{
'anum' => 'A056106',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A056108',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed',
'line_type',
'X_neg'
]
},
{
'anum' => 'A056109',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed',
'line_type',
'Y_neg'
]
},
{
'anum' => 'A056107',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A049451',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed,n_start=0',
'line_type',
'X_neg'
]
},
{
'anum' => 'A062783',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A063436',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HexSpiralSkewed,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A022265',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HeptSpiralSkewed,n_start=0',
'line_type',
'X_neg'
]
},
{
'anum' => 'A195023',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HeptSpiralSkewed,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A022264',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HeptSpiralSkewed,n_start=0',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A186029',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HeptSpiralSkewed,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A024966',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HeptSpiralSkewed,n_start=0',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A139273',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A139275',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'X_neg'
]
},
{
'anum' => 'A139277',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'Y_neg'
]
},
{
'anum' => 'A139272',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A139274',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A139276',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'OctagramSpiral,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A033570',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral'
]
},
{
'anum' => 'A033568',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A085473',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A126587',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral',
'line_type',
'Y_axis',
'i_start',
1
]
},
{
'anum' => 'A139267',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A049452',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'X_neg'
]
},
{
'anum' => 'A033580',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'Y_neg'
]
},
{
'anum' => 'A094159',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A049453',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'Diagonal_SW'
]
},
{
'anum' => 'A195319',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'AnvilSpiral,n_start=0',
'line_type',
'Diagonal_SE'
]
},
{
'anum' => 'A051132',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Hypot,n_start=0'
]
},
{
'anum' => 'A036702',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HypotOctant,points=even',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A007051',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PythagoreanTree',
'line_type',
'Depth_start'
]
},
{
'anum' => 'A081254',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Bird'
]
},
{
'anum' => 'A086893',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'RationalsTree,tree_type=Drib'
]
},
{
'anum' => 'A102631',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'FactorRationals',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A163480',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PeanoCurve'
]
},
{
'anum' => 'A163481',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PeanoCurve',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A163343',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PeanoCurve',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A163482',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HilbertCurve'
]
},
{
'anum' => 'A163483',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'HilbertCurve',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A062880',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'ZOrderCurve',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A001196',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'ZOrderCurve',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A037314',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'ZOrderCurve,radix=3',
'i_start',
1
]
},
{
'anum' => 'A051022',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'ZOrderCurve,radix=10'
]
},
{
'anum' => 'A163344',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'GrayCode,apply_type=sT,radix=3',
'line_type',
'X_axis'
]
},
{
'anum' => 'A006046',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SierpinskiTriangle,align=diagonal,n_start=0',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A074330',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'SierpinskiTriangle',
'line_type',
'Diagonal',
'i_start',
1
]
},
{
'anum' => 'A066321',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'ComplexMinus'
]
},
{
'anum' => 'A016777',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Rows,width=3',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A016813',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Rows,width=4',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A016861',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Rows,width=5',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A016921',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Rows,width=6',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A016993',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Rows,width=7',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A000124',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Diagonals',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A001844',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Diagonals',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A096376',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Staircase,n_start=2',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A059100',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Corner,n_start=2',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A014206',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Corner,n_start=2',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A028552',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Corner,wider=2,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A028387',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'Corner,wider=2,n_start=1',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A104249',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidRows,step=3',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A143689',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidRows,step=3',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A084849',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidRows,step=4',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A046092',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidRows,step=4,n_start=0',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A002522',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PyramidSides',
'line_type',
'X_neg'
]
},
{
'anum' => 'A061925',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'CellularRule,rule=5',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A006578',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'CellularRule190,n_start=0',
'line_type',
'Diagonal_NW'
]
},
{
'anum' => 'A147562',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'UlamWarburton,n_start=0',
'line_type',
'Depth_start'
]
},
{
'anum' => 'A183060',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'UlamWarburton,parts=2,n_start=0',
'line_type',
'Depth_start'
]
},
{
'anum' => 'A151922',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'UlamWarburton,parts=1,n_start=1',
'line_type',
'Depth_end'
]
},
{
'anum' => 'A151920',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'UlamWarburtonQuarter',
'line_type',
'Depth_end'
]
},
{
'anum' => 'A084471',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'DigitGroups,radix=2',
'i_start',
1
]
},
{
'anum' => 'A003622',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'WythoffArray,x_start=1,y_start=1',
'line_type',
'Y_axis'
]
},
{
'anum' => 'A020941',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'WythoffArray,x_start=1,y_start=1',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A014480',
'class' => 'Math::NumSeq::PlanePathN',
'parameters' => [
'planepath',
'PowerArray',
'line_type',
'Diagonal'
]
},
{
'anum' => 'A163536',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'PeanoCurve',
'turn_type',
'SLR'
]
},
{
'anum' => 'A163537',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'PeanoCurve',
'turn_type',
'SRL'
]
},
{
'anum' => 'A163542',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'HilbertCurve',
'turn_type',
'SLR'
]
},
{
'anum' => 'A163543',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'HilbertCurve',
'turn_type',
'SRL'
]
},
{
'anum' => 'A035263',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'KochCurve'
]
},
{
'anum' => 'A056832',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'KochCurve',
'turn_type',
'SLR'
]
},
{
'anum' => 'A034947',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'DragonCurve',
'turn_type',
'LSR'
]
},
{
'anum' => 'A099545',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'DragonCurve',
'turn_type',
'Turn4'
]
},
{
'anum' => 'A209615',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'AlternatePaper',
'turn_type',
'LSR'
]
},
{
'anum' => 'A137893',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'GosperSide'
]
},
{
'anum' => 'A060236',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'GosperSide',
'turn_type',
'SLR'
]
},
{
'anum' => 'A129184',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'Diagonals,n_start=0'
]
},
{
'anum' => 'A156319',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'Diagonals,n_start=0',
'turn_type',
'srl'
]
},
{
'anum' => 'A000007',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'Corner,wider=1,n_start=-1'
]
},
{
'anum' => 'A063524',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'Corner,wider=2,n_start=-1'
]
},
{
'anum' => 'A185012',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'Corner,wider=3,n_start=-1'
]
},
{
'anum' => 'A176040',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'CellularRule,rule=84,n_start=-1',
'turn_type',
'Turn4'
]
},
{
'anum' => 'A131534',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'CellularRule,rule=6,n_start=-1',
'turn_type',
'SRL'
]
},
{
'anum' => 'A130196',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'CellularRule,rule=20,n_start=-1',
'turn_type',
'SRL'
]
},
{
'anum' => 'A156596',
'class' => 'Math::NumSeq::PlanePathTurn',
'parameters' => [
'planepath',
'FibonacciWordFractal',
'turn_type',
'SRL'
]
}
]
;
1;
__END__
Math-PlanePath-113/lib/Math/NumSeq/PlanePathTurn.pm 0000644 0001750 0001750 00000231101 12250720133 017622 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --values=PlanePathTurn
#
# maybe:
# Turn4 0,1,2,3 and fractional
# Turn4n 0,1,2,-1 negatives Turn4mid Turn4n Turn4s
# TTurn6n 0,1,2,3, -1,-2, eg. flowsnake TTurn6s
# TTurn6 0,1,2,3,4,5
package Math::NumSeq::PlanePathTurn;
use 5.004;
use strict;
use Carp;
use vars '$VERSION','@ISA';
$VERSION = 113;
use Math::NumSeq;
@ISA = ('Math::NumSeq');
use Math::NumSeq::PlanePathCoord;
use Math::PlanePath;
use Math::PlanePath::Base::Generic
'is_infinite';
use Math::NumSeq::PlanePathDelta;
# uncomment this to run the ### lines
# use Smart::Comments;
use constant characteristic_smaller => 1;
sub description {
my ($self) = @_;
if (ref $self) {
return "Turn values $self->{'turn_type'} from path $self->{'planepath'}";
} else {
# class method
return 'Turns from a PlanePath';
}
}
use constant::defer parameter_info_array =>
sub {
return [
Math::NumSeq::PlanePathCoord::_parameter_info_planepath(),
{
name => 'turn_type',
display => 'Turn Type',
type => 'enum',
default => 'Left',
choices => ['Left','Right','LSR','SLR','SRL',
# 'RSL',
# 'Straight',
# 'Turn4', # Turn4 is 0<=value<4.
# 'Turn4n',
# 'TTurn6',
],
description => 'Left is 1=left, 0=right or straight.
Right is 1=right, 0=left or straight.
LSR is 1=left,0=straight,-1=right.
SLR is 0=straight,1=left,2=right.
SRL is 0=straight,1=right,2=left.',
},
];
};
sub characteristic_integer {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $func = $planepath_object->can("_NumSeq_Turn_$self->{'turn_type'}_integer")) {
return $planepath_object->$func();
}
return undef;
}
#------------------------------------------------------------------------------
sub oeis_anum {
my ($self) = @_;
### PlanePathTurn oeis_anum() ...
my $planepath = $self->{'planepath_object'};
my $key = Math::NumSeq::PlanePathCoord::_planepath_oeis_anum_key($self->{'planepath_object'});
### planepath: ref $planepath
### $key
### whole table: $planepath->_NumSeq_Turn_oeis_anum
### key href: $planepath->_NumSeq_Turn_oeis_anum->{$key}
return $planepath->_NumSeq_Turn_oeis_anum->{$key}->{$self->{'turn_type'}};
}
#------------------------------------------------------------------------------
sub new {
### PlanePathTurn new(): @_
my $self = shift->SUPER::new(@_);
### self from SUPER: $self
$self->{'planepath_object'}
||= Math::NumSeq::PlanePathCoord::_planepath_name_to_object($self->{'planepath'});
### turn_func: "_turn_func_$self->{'turn_type'}", $self->{'turn_func'}
$self->{'turn_func'} = $self->can('_turn_func_'.$self->{'turn_type'})
|| croak "Unrecognised turn_type: ",$self->{'turn_type'};
$self->rewind;
### $self
return $self;
}
sub i_start {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'} || return 0;
return $planepath_object->n_start + $planepath_object->arms_count;
}
sub rewind {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'} || return;
$self->{'i'} = $self->i_start;
$self->{'arms'} = $planepath_object->arms_count;
undef $self->{'prev_dx'};
}
sub next {
my ($self) = @_;
### NumSeq-PlanePathTurn next(): "i=$self->{'i'}"
my $planepath_object = $self->{'planepath_object'};
my $i = $self->{'i'}++;
my $arms = $self->{'arms'};
my $prev_dx = $self->{'prev_dx'};
my $prev_dy;
if (defined $prev_dx) {
$prev_dy = $self->{'prev_dy'};
### use prev dxdy: "$prev_dx,$prev_dy"
} else {
($prev_dx, $prev_dy) = $planepath_object->n_to_dxdy($i-$arms)
or do {
### nothing in path at n: $i
return;
};
### calc prev dxdy: "at i=".($i-$arms)." $prev_dx,$prev_dy"
}
my ($dx, $dy) = $planepath_object->n_to_dxdy($i)
or do {
### nothing in path at previous n: $i-$arms
return;
};
### calc dxdy: "at i=$i $dx,$dy"
if ($arms == 1) {
$self->{'prev_dx'} = $dx;
$self->{'prev_dy'} = $dy;
}
return ($i, $self->{'turn_func'}->($prev_dx,$prev_dy, $dx,$dy));
}
sub ith {
my ($self, $i) = @_;
### PlanePathTurn ith(): $i
if (is_infinite($i)) {
return undef;
}
my $planepath_object = $self->{'planepath_object'};
my $arms = $self->{'arms'};
my ($prev_dx, $prev_dy) = $planepath_object->n_to_dxdy($i - $arms)
or return undef;
my ($dx, $dy) = $planepath_object->n_to_dxdy($i)
or return undef;
return $self->{'turn_func'}->($prev_dx,$prev_dy, $dx,$dy);
}
# dx1,dy1
# dx2,dy2 /
# * /
# /
# /
# /
# /
# O
#
# cmpy = dx2 * dy1/dx1
# left if dy2 > cmpy
# dy2 > dx2 * dy1/dx1
# dy2 * dx1 > dx2 * dy1
#
# if dx1=0, dy1 > 0 then left if dx2 < 0
# dy2 * 0 > dx2 * dy1
# 0 > dx2*dy1 good
#
sub _turn_func_Left {
my ($dx,$dy, $next_dx,$next_dy) = @_;
### _turn_func_Left() ...
return ($next_dy * $dx > $next_dx * $dy ? 1 : 0);
}
sub _turn_func_Right {
my ($dx,$dy, $next_dx,$next_dy) = @_;
### _turn_func_Right() ...
return ($next_dy * $dx < $next_dx * $dy ? 1 : 0);
}
sub _turn_func_LSR {
my ($dx,$dy, $next_dx,$next_dy) = @_;
### _turn_func_LSR() ...
return (($next_dy * $dx <=> $next_dx * $dy) || 0); # 1,0,-1
}
sub _turn_func_RSL {
return - _turn_func_LSR(@_);
}
{
my @LSR_to_SLR = (0, # LSR=0 straight -> SLR=0
1, # LSR=1 left -> SLR=1
2); # LSR=-1 right -> SLR=2
sub _turn_func_SLR {
return $LSR_to_SLR[_turn_func_LSR(@_)];
}
}
{
my @LSR_to_SRL = (0, # LSR=0 straight -> SRL=0
2, # LSR=1 left -> SRL=2
1); # LSR=-1 right -> SRL=1
sub _turn_func_SRL {
return $LSR_to_SRL[_turn_func_LSR(@_)];
}
}
sub _turn_func_Straight {
my ($dx,$dy, $next_dx,$next_dy) = @_;
### _turn_func_Left() ...
return ($next_dy * $dx == $next_dx * $dy ? 1 : 0);
}
# sub _turn_func_LR_01 {
# my ($dx,$dy, $next_dx,$next_dy) = @_;
# ### _turn_func_LR_01() ...
# return ($next_dy * $dx >= $next_dx * $dy || 0);
# }
sub _turn_func_Turn4 {
my ($dx,$dy, $next_dx,$next_dy) = @_;
### _turn_func_Turn4(): "$dx,$dy $next_dx,$next_dy"
return
(((Math::NumSeq::PlanePathDelta::_delta_func_Dir360($next_dx,$next_dy)
- Math::NumSeq::PlanePathDelta::_delta_func_Dir360($dx,$dy)) % 360)
/ 90);
}
sub _turn_func_Turn4n {
my ($dx,$dy, $next_dx,$next_dy) = @_;
require Math::NumSeq::PlanePathDelta;
my $ret
= (((Math::NumSeq::PlanePathDelta::_delta_func_Dir360($next_dx,$next_dy)
- Math::NumSeq::PlanePathDelta::_delta_func_Dir360($dx,$dy)) % 360)
/ 90);
if ($ret > 2) { $ret -= 4; }
return $ret;
}
sub _turn_func_TTurn6 {
my ($dx,$dy, $next_dx,$next_dy) = @_;
require Math::NumSeq::PlanePathDelta;
return
(((Math::NumSeq::PlanePathDelta::_delta_func_TDir360($next_dx,$next_dy)
- Math::NumSeq::PlanePathDelta::_delta_func_TDir360($dx,$dy)) % 360)
/ 60);
}
sub pred {
my ($self, $value) = @_;
### PlanePathTurn pred(): $value
my $planepath_object = $self->{'planepath_object'};
if (defined (my $values_min = $self->values_min)) {
if ($value < $values_min) {
return 0;
}
}
if (defined (my $values_max = $self->values_max)) {
if ($value > $values_max) {
return 0;
}
}
my $turn_type = $self->{'turn_type'};
if ($turn_type eq 'Left' || $turn_type eq 'Right' || $turn_type eq 'Straight') {
unless ($value == 0 || $value == 1) {
return 0;
}
} elsif ($turn_type eq 'LSR' || $turn_type eq 'RSL') {
unless ($value == 1 || $value == 0 || $value == -1) {
return 0;
}
} else { # ($turn_type eq 'SLR' || $turn_type eq 'SRL') {
unless ($value == 0 || $value == 1 || $value == 2) {
return 0;
}
}
if (my $func = $planepath_object->can('_NumSeq_Turn_'.$self->{'turn_type'}.'_pred_hash')) {
my $href = $self->$func();
unless ($href->{$value}) {
return 0;
}
}
return 1;
}
#------------------------------------------------------------------------------
sub values_min {
my ($self) = @_;
my $method = '_NumSeq_Turn_' . $self->{'turn_type'} . '_min';
return $self->{'planepath_object'}->can($method)
? $self->{'planepath_object'}->$method()
: undef;
}
sub values_max {
my ($self) = @_;
my $method = '_NumSeq_Turn_' . $self->{'turn_type'} . '_max';
return $self->{'planepath_object'}->can($method)
? $self->{'planepath_object'}->$method()
: undef;
}
sub characteristic_increasing {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $func = $planepath_object->can("_NumSeq_Turn_$self->{'turn_type'}_increasing")) {
return $planepath_object->$func();
}
return undef; # unknown
}
sub characteristic_non_decreasing {
my ($self) = @_;
my $planepath_object = $self->{'planepath_object'};
if (my $func = $planepath_object->can("_NumSeq_Turn_$self->{'turn_type'}_non_decreasing")) {
return $planepath_object->$func();
}
if (defined (my $values_min = $self->values_min)) {
if (defined (my $values_max = $self->values_max)) {
if ($values_min == $values_max) {
# constant seq is non-decreasing
return 1;
}
}
}
# increasing means non_decreasing too
return $self->characteristic_increasing;
}
# my $all_Left_predhash = { 0=>1, 1=>1 };
# my $all_LSR_predhash = { 0=>1, 1=>1, -1=>1 };
# my $straight_Left_predhash = { 0=>1 };
# my $straight_LSR_predhash = { 0=>1 };
{ package Math::PlanePath;
use constant 1.02; # for leading underscore
use constant _NumSeq_Turn_Left_min => 0;
use constant _NumSeq_Turn_Left_max => 1;
use constant _NumSeq_Turn_Left_integer => 1;
use constant _NumSeq_Turn_Right_min => 0;
use constant _NumSeq_Turn_Right_max => 1;
use constant _NumSeq_Turn_Right_integer => 1;
use constant _NumSeq_Turn_LSR_min => -1;
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_LSR_integer => 1;
# Right_min == 1 then always Right
# Left_min == 1 then always Left
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return (($self->_NumSeq_Turn_Right_min && 2) # if always Right
|| $self->_NumSeq_Turn_Left_min); # 0,1 Left
}
sub _NumSeq_Turn_SLR_max {
my ($self) = @_;
return (($self->_NumSeq_Turn_Right_max && 2) # if always Right
|| $self->_NumSeq_Turn_Left_max); # 0,1 Left
}
use constant _NumSeq_Turn_SLR_integer => 1;
sub _NumSeq_Turn_SRL_min {
my ($self) = @_;
return (($self->_NumSeq_Turn_Left_min && 2) # if always Left
|| $self->_NumSeq_Turn_Right_min); # 0,1 Right
}
sub _NumSeq_Turn_SRL_max {
my ($self) = @_;
return (($self->_NumSeq_Turn_Left_max && 2) # if always Left
|| $self->_NumSeq_Turn_Right_max); # 0,1 Right
}
use constant _NumSeq_Turn_SRL_integer => 1;
use constant _NumSeq_Turn_Turn4_min => 0;
sub _NumSeq_Turn_Turn4_integer {
my ($self) = @_;
return $self->_NumSeq_Delta_Dir4_integer;
}
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->_NumSeq_Turn_Turn4_integer ? 3 : 4);
}
use constant _NumSeq_Turn_oeis_anum => {};
}
{ package Math::PlanePath::SquareSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1; # left or straight
# SquareSpiral
# abs(A167752)==Left=LSR=Turn4 if that really is the quarter-squares
# abs(A167753)==Left=LSR=Turn4 of wider=1 if that really is the ceil(n+1)^2
}
{ package Math::PlanePath::GreekKeySpiral;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'turns'} == 0 ? 0 # SquareSpiral, left or straight only
: -1); # any left,straight,right
}
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
return ($self->{'turns'} == 0 ? 0 # SquareSpiral, left or straight only
: 1);
}
sub _NumSeq_Turn_Right_non_decreasing {
my ($self) = @_;
return ($self->{'turns'} == 0 ? 1 # SquareSpiral, left or straight only
: 0);
}
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'turns'} == 0
? 1 # SquareSpiral, left or straight only
: 3); # otherwise turn right too
}
}
{ package Math::PlanePath::PyramidSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
}
{ package Math::PlanePath::TriangleSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
use constant _NumSeq_Turn_oeis_anum =>
{ 'n_start=-1' =>
{ Left => 'A023531', # 1 at k*(k+3)/2
LSR => 'A023531',
Straight => 'A023532', # 0 at k*(k+3)/2, 1 otherwise
# OEIS-Other: A023531 planepath=TriangleSpiral,n_start=-1
# OEIS-Other: A023531 planepath=TriangleSpiral,n_start=-1 turn_type=LSR
# OEIS-Other: A023532 planepath=TriangleSpiral,n_start=-1 turn_type=Straight
},
};
}
{ package Math::PlanePath::TriangleSpiralSkewed;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
use constant _NumSeq_Turn_oeis_anum =>
{
do {
my $href = { Left => 'A023531', # 1 at k*(k+3)/2
LSR => 'A023531',
Straight => 'A023532', # 0 at k*(k+3)/2, 1 otherwise
};
('skew=left,n_start=-1' => $href,
'skew=right,n_start=-1' => $href,
'skew=up,n_start=-1' => $href,
'skew=down,n_start=-1' => $href)
# OEIS-Other: A023531 planepath=TriangleSpiralSkewed,n_start=-1
# OEIS-Other: A023531 planepath=TriangleSpiralSkewed,n_start=-1 turn_type=LSR
# OEIS-Other: A023532 planepath=TriangleSpiralSkewed,n_start=-1 turn_type=Straight
# OEIS-Other: A023531 planepath=TriangleSpiralSkewed,n_start=-1,skew=right
# OEIS-Other: A023531 planepath=TriangleSpiralSkewed,n_start=-1,skew=up
# OEIS-Other: A023531 planepath=TriangleSpiralSkewed,n_start=-1,skew=down
},
};
}
{ package Math::PlanePath::DiamondSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
}
{ package Math::PlanePath::AztecDiamondRings;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1; # left or straight
}
{ package Math::PlanePath::PentSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max =>
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(2,0, -2,1);
}
{ package Math::PlanePath::PentSpiralSkewed;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
}
{ package Math::PlanePath::HexSpiral;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
}
{ package Math::PlanePath::HexSpiralSkewed;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5;
}
{ package Math::PlanePath::HeptSpiralSkewed;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1.5; # at N=2 turn +135
}
{ package Math::PlanePath::AnvilSpiral;
use constant _NumSeq_Turn_Turn4_max => 3;
}
{ package Math::PlanePath::OctagramSpiral;
use constant _NumSeq_Turn_Turn4_max => 3; # +90 right
}
{ package Math::PlanePath::KnightSpiral;
# use constant _NumSeq_Turn_Turn4_min => ...; # 2,1
}
# { package Math::PlanePath::CretanLabyrinth;
# }
{ package Math::PlanePath::SquareArms;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1; # left or straight
}
{ package Math::PlanePath::DiamondArms;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1; # left or straight
use constant _NumSeq_Turn_Turn4_integer => 1;
}
{ package Math::PlanePath::HexArms;
use constant _NumSeq_Turn_LSR_min => 0; # left or straight
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_Right_max => 0; # left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn_Turn4_max => 1; # at N=8
}
{ package Math::PlanePath::SacksSpiral;
use constant _NumSeq_Turn_Left_min => 1; # left always
use constant _NumSeq_Turn_Left_max => 1;
use constant _NumSeq_Turn_Left_non_decreasing => 1;
use constant _NumSeq_Turn_LSR_min => 1;
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_LSR_non_decreasing => 1;
use constant _NumSeq_Turn_Right_max => 0; # left always
use constant _NumSeq_Turn_Right_non_decreasing => 1;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
# at N=1 is maximum turn
return Math::NumSeq::PlanePathTurn::_turn_func_Turn4(1,0,
$self->n_to_dxdy(1));
}
use constant _NumSeq_Turn4_min_is_infimum => 1;
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ 'Left' => 'A000012', # left always, all ones
'LSR' => 'A000012',
# OEIS-Other: A000012 planepath=SacksSpiral
# OEIS-Other: A000012 planepath=SacksSpiral turn_type=LSR
},
};
}
{ package Math::PlanePath::VogelFloret;
sub _NumSeq_Turn_Left_min { # always left if rot<=0.5
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? 0 : 1);
}
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? 0 : 1);
}
use constant _NumSeq_Turn_Left_non_decreasing => 1; # constant 0 or 1
sub _NumSeq_Turn_Right_min { # always right if rot>0.5
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? 1 : 0);
}
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? 1 : 0);
}
use constant _NumSeq_Turn_Right_non_decreasing => 1; # constant 0 or 1
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? -1 : 1);
}
sub _NumSeq_Turn_LSR_max {
my ($self) = @_;
return ($self->{'rotation_factor'} > 0.5 ? -1 : 1);
}
use constant _NumSeq_Turn_LSR_non_decreasing => 1; # constant 1 or -1
# sub _NumSeq_Turn_LSR_pred_hash {
# my ($self) = @_;
# return ($self->{'rotation_factor'} > 0.5 ? 1 : 0);
# }
}
{ package Math::PlanePath::TheodorusSpiral;
use constant _NumSeq_Turn_Left_min => 1; # left always
use constant _NumSeq_Turn_Left_max => 1;
use constant _NumSeq_Turn_Left_non_decreasing => 1;
use constant _NumSeq_Turn_LSR_min => 1;
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_LSR_non_decreasing => 1;
use constant _NumSeq_Turn_Right_max => 0; # left always
use constant _NumSeq_Turn_Right_non_decreasing => 1;
use constant _NumSeq_Turn4_min_is_infimum => 1; # approaches straight
use constant _NumSeq_Turn_Turn4_max => 1; # initial 90deg
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ 'Left' => 'A000012', # left always, all ones
'LSR' => 'A000012',
# OEIS-Other: A000012 planepath=TheodorusSpiral
# OEIS-Other: A000012 planepath=TheodorusSpiral turn_type=LSR
},
};
}
{ package Math::PlanePath::ArchimedeanChords;
use constant _NumSeq_Turn_Left_min => 1; # left always
use constant _NumSeq_Turn_Left_max => 1;
use constant _NumSeq_Turn_Left_non_decreasing => 1;
use constant _NumSeq_Turn_LSR_min => 1;
use constant _NumSeq_Turn_LSR_max => 1;
use constant _NumSeq_Turn_LSR_non_decreasing => 1;
use constant _NumSeq_Turn_Right_max => 0; # left always
use constant _NumSeq_Turn_Right_non_decreasing => 1;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
# at N=1 is maximum turn
return Math::NumSeq::PlanePathTurn::_turn_func_Turn4(1,0,
$self->n_to_dxdy(1));
}
use constant _NumSeq_Turn4_min_is_infimum => 1; # approaches straight ahead
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ 'Left' => 'A000012', # left always, all ones
'LSR' => 'A000012',
# OEIS-Other: A000012 planepath=ArchimedeanChords
# OEIS-Other: A000012 planepath=ArchimedeanChords turn_type=LSR
},
};
}
{ package Math::PlanePath::MultipleRings;
# step=1 and step=2 are mostly 1 for left, but after a while each ring
# endpoint is to the right
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'step'} <= 0
? 0 # step == 0 is always straight ahead
: 1);
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
# step=0 always straight
# step=1 straight,straight, then always left
return ($self->{'step'} <= 1);
}
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
# step=0 is always straight ahead
# step=1 is never right
return ($self->{'step'} <= 1
? 0
: 1);
}
*_NumSeq_Turn_Right_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'step'} <= 1
? 0 # step == 0 is always straight ahead
: -1);
}
*_NumSeq_Turn_LSR_max = \&_NumSeq_Turn_Left_max;
*_NumSeq_Turn_LSR_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
# step=0 straight line
# step=1 straight at N=2
# step=2 straight at N=2
return ($self->{'step'} <= 2 ? 0
: $self->{'ring_shape'} eq 'circle' ? 1 # never straight
: 0); # ring_shape=polygon sides straight
}
sub _NumSeq_Turn_SLR_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 # straight line only
: $self->{'step'} == 1 ? 1
: 2);
}
sub _NumSeq_Turn_SLR_non_decreasing {
my ($self) = @_;
return ($self->{'step'} <= 1 ? 1 # straight line only
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
sub _NumSeq_Turn_SRL_max {
my ($self) = @_;
return ($self->{'step'} == 0 ? 0 # straight line only
: 2);
}
*_NumSeq_Turn_SRL_non_decreasing = \&_NumSeq_Turn_SLR_non_decreasing;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
my $step = $self->{'step'};
return ($step == 0
? 0 # step == 0 is always straight ahead
: 4/$step);
}
use constant _NumSeq_Turn_oeis_anum =>
{
# MultipleRings step=0 is trivial X=N,Y=0
'step=0,ring_shape=circle' =>
{ Left => 'A000004', # all-zeros
LSR => 'A000004', # all zeros, straight
# OEIS-Other: A000004 planepath=MultipleRings,step=0
# OEIS-Other: A000004 planepath=MultipleRings,step=0 turn_type=LSR
},
'step=0,ring_shape=polygon' =>
{ Left => 'A000004', # all-zeros
LSR => 'A000004', # all zeros, straight
# OEIS-Other: A000004 planepath=MultipleRings,step=0,ring_shape=polygon
# OEIS-Other: A000004 planepath=MultipleRings,step=0,ring_shape=polygon turn_type=LSR
},
};
}
{ package Math::PlanePath::PixelRings;
# has right turns between rings
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::FilledRings;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::Hypot;
sub _NumSeq_Turn_Left_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # all, left always
: 0); # odd,even left or straight
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # all, left always
: 0); # odd,even any
}
use constant _NumSeq_Turn_Right_max => 0; # always left or straight
use constant _NumSeq_Turn_Right_non_decreasing => 1;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'points'} eq 'all'
? 1 # all, left always
: 0); # odd,even left or straight
}
*_NumSeq_Turn_LSR_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn4_min_is_infimum {
my ($self) = @_;
return ($self->{'points'} eq 'all');
}
{
my %_NumSeq_Turn_Turn4_max
= (all => 1.5, # at N=2, apparent maximum
even => 1.5, # at N=2, apparent maximum
odd => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(3,-3, 3,5),
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($_NumSeq_Turn_Turn4_max{$self->{'points'}} || 0);
}
}
}
{ package Math::PlanePath::HypotOctant;
# apparently approaches +360 degrees
use constant _NumSeq_Turn4_max_is_supremum => 1;
}
{ package Math::PlanePath::TriangularHypot;
sub _NumSeq_Turn_Left_min {
my ($self) = @_;
return ($self->{'points'} eq 'hex'
? 1 # hex, left always
: 0); # other, various left/right
}
*_NumSeq_Turn_Left_non_decreasing = \&_NumSeq_Turn_Left_min;
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
return ($self->{'points'} =~ /hex|even/
? 0 # even,hex, left or straight, so Right=0 always
: 1); # odd,all both left or right
}
sub _NumSeq_Turn_Right_non_decreasing {
my ($self) = @_;
return ($self->{'points'} =~ /hex|even/
? 1 # even,hex, left or straight, so Right=0 always
: 0); # odd,all both left or right
}
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'points'} eq 'hex'
? 1 # hex, left always
: $self->{'points'} =~ /even|hex_/
? 0 # even,hex, left or straight
: -1); # odd,all any
}
*_NumSeq_Turn_LSR_non_decreasing = \&_NumSeq_Turn_Left_min;
{
my %_NumSeq_Turn_SLR_min = (odd => 1, # never straight
hex => 1, # always left
);
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($_NumSeq_Turn_SLR_min{$self->{'points'}} || 0);
}
}
{
my %_NumSeq_Turn_SRL_min = (odd => 1, # never straight
hex => 2, # always left
);
sub _NumSeq_Turn_SRL_min {
my ($self) = @_;
return ($_NumSeq_Turn_SRL_min{$self->{'points'}} || 0);
}
}
# points=even Turn4=0 at N=31
#
# points=all apparently approaches 0
# min i=473890[1303230202] 0.00000 px=-11,py=1 dx=-13,dy=1 -13.000
#
# points=odd apparently approaches 0
# min i=95618[113112002] 0.01111 px=-14,py=4 dx=-16,dy=4 -4.000
#
# points=hex apparently approaches 0
# min i=44243[22303103] 0.01111 px=-15,py=3 dx=-12,dy=2 -6.000
#
# points=hex_rotated Turn4=0 at N=58
# points=hex_centred Turn4=0 at N=24
{
my %_NumSeq_Turn4_min_is_infimum = (all => 1,
odd => 1,
hex => 1,
);
sub _NumSeq_Turn4_min_is_infimum {
my ($self) = @_;
return ($_NumSeq_Turn4_min_is_infimum{$self->{'points'}} || 0);
}
}
{
my %_NumSeq_Turn_Turn4_max
= (even => 1.5, # at N=2
odd => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(5,3, 0,-6),
all => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(5,3, 0,-6),
hex => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(2,0, -3,1),
hex_rotated => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(1,1, -3,-1),
hex_centred => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(3,1, -2,2),
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($_NumSeq_Turn_Turn4_max{$self->{'points'}} || 0);
}
}
}
{ package Math::PlanePath::PythagoreanTree;
{
my %UAD_coordinates_always_right = (PQ => 1,
AB => 1,
AC => 1);
sub _NumSeq_Turn_always_Right {
my ($self) = @_;
return ($self->{'tree_type'} eq 'UAD'
&& $UAD_coordinates_always_right{$self->{'coordinates'}});
}
}
{
my %UAD_coordinates_always_left = (BC => 1);
sub _NumSeq_Turn_always_Left {
my ($self) = @_;
return ($self->{'tree_type'} eq 'UAD'
&& $UAD_coordinates_always_left{$self->{'coordinates'}});
}
}
{
my %UMT_coordinates_any_straight = (BC => 1, # UMT at N=5
PQ => 1); # UMT at N=5
sub _NumSeq_Turn_never_straight {
my ($self) = @_;
return ($self->{'tree_type'} eq 'UMT'
&& $UMT_coordinates_any_straight{$self->{'coordinates'}}
? 0 : 1);
}
}
sub _NumSeq_Turn_Left_min {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self) ? 1 : 0);
}
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return (_NumSeq_Turn_always_Right($self) ? 0 : 1);
}
sub _NumSeq_Turn_Right_min {
my ($self) = @_;
return (_NumSeq_Turn_always_Right($self) ? 1 : 0);
}
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self) ? 0 : 1);
}
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self) ? 1 : -1);
}
sub _NumSeq_Turn_LSR_max {
my ($self) = @_;
return (_NumSeq_Turn_always_Right($self) ? -1 : 1);
}
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return (_NumSeq_Turn_always_Right($self) ? 2
: $self->_NumSeq_Turn_never_straight);
}
sub _NumSeq_Turn_SLR_max {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self) ? 1 : 2);
}
sub _NumSeq_Turn_SRL_min {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self) ? 2
: $self->_NumSeq_Turn_never_straight);
}
sub _NumSeq_Turn_SRL_max {
my ($self) = @_;
return (_NumSeq_Turn_always_Right($self) ? 1 : 2);
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return (_NumSeq_Turn_always_Left($self)
|| _NumSeq_Turn_always_Right($self)
? 1 : 0);
}
*_NumSeq_Turn_Right_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
*_NumSeq_Turn_LSR_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
# A000004 all-zeros and A000012 all-ones are OFFSET=0 which doesn't match
# start N=1 here for always turn left or right in UAD.
}
{ package Math::PlanePath::RationalsTree;
{
my %_NumSeq_Turn_SLR_min = (SB => 1,
CW => 1,
# Bird => 0, # straight at N=7 and N=8
Drib => 1,
# AYT => 0, # straight at N=7
HCS => 1,
L => 1);
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($_NumSeq_Turn_SLR_min{$self->{'tree_type'}} || 0);
}
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
# SB turn cf A021913 0,0,1,1
# A133872 1,1,0,0
# A057077 1,1,-1,-1
# A087960 1,-1,-1,1
# HCS turn left close to A010059 thue-morse or A092436
# right A010060
# LSR => 'A106400', # thue-morse +/-1
# CfracDigits radix=1 likewise
}
# { package Math::PlanePath::FractionsTree;
# }
{ package Math::PlanePath::ChanTree;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
# # FIXME: k=4,5,6 are Right-only, maybe
# # sub _NumSeq_Turn_Left_max {
# # my ($self) = @_;
# # return ($self->{'k'} >= 4
# # ? 0 # never Left
# # : 1);
# # }
# # sub _NumSeq_Turn_Right_min {
# # my ($self) = @_;
# # return ($self->{'k'} >= 4
# # ? 1 # always Right
# # : 0);
# # }
# # sub _NumSeq_Turn_LSR_max {
# # my ($self) = @_;
# # return ($self->{'k'} >= 4
# # ? -1 # always Right
# # : 1);
# # }
}
{ package Math::PlanePath::DiagonalRationals;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? 2.5 # N=2
: Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-1,1, 2,-1)); # N=3
}
}
# { package Math::PlanePath::FactorRationals;
# # revbinary
# # max i=296[10220] 3.98889 px=-258,py=1 dx=-26,dy=1[-122,1] -26.000
# N=295=5*59 X=5*59 Y=1 N=297
# N=296=2^3*37 X=37 Y=2 -26,+1 \ N=296 <-------- N=295
# N=297=3^3*11 X=11 Y=3 -258,+1
# }
{ package Math::PlanePath::GcdRationals;
# Turn4 minimum
# pairs_order=rows
# min=0 at N=12
# max i=216[3120] 3.98889 px=11,py=-14 dx=3,dy=-4[3,-10] -0.750
#
# pairs_order=rows_reverse
# min i=13[31] 0.00000 px=-1,py=0 dx=-1,dy=0 0.000
# max i=611[21203] 3.98889 px=-1,py=2 dx=-13,dy=28[-31,130] -0.464
#
# pairs_order=diagonals_down
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=561[20301] 3.98889 px=-7,py=8 dx=-5,dy=6[-11,12] -0.833
#
# pairs_order=diagonals_up
# min i=11[23] 0.00000 px=-1,py=1 dx=-1,dy=1 -1.000
# max i=4886[1030112] 3.98889 px=6,py=-6 dx=15,dy=-16[33,-100] -0.938
#
# Are these exact maximums or more when bigger N?
}
{ package Math::PlanePath::CfracDigits;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 1
? 1 # never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::AR2W2Curve; # NSEW+diag
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::PeanoCurve;
use constant _NumSeq_Turn_oeis_anum =>
{ 'radix=3' =>
{
# 2---0---0---0---0---2
# | |
# 2---0---1 1---0---2
# | |
# .---0---1 1---0---0-...
SLR => 'A163536', # turn 0=ahead,1=left,2=right, OFFSET=1
SRL => 'A163537',
# OEIS-Catalogue: A163536 planepath=PeanoCurve turn_type=SLR
# OEIS-Catalogue: A163537 planepath=PeanoCurve turn_type=SRL
# Not quite, A039963 is OFFSET=0 vs first turn N=1 here
# Straight => 'A039963',
},
};
}
# { package Math::PlanePath::WunderlichSerpentine;
# }
{ package Math::PlanePath::HilbertCurve;
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ SLR => 'A163542', # relative direction ahead=0,left=1,right=2 OFFSET=1
SRL => 'A163543', # relative direction transpose
# OEIS-Catalogue: A163542 planepath=HilbertCurve turn_type=SLR
# OEIS-Catalogue: A163543 planepath=HilbertCurve turn_type=SRL
},
};
}
{ package Math::PlanePath::ZOrderCurve;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 2
? 1 # radix=2 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
sub _NumSeq_Turn_Turn4_min {
my ($self) = @_;
return ($self->{'radix'} == 2
? 0.5
: 0); # includes straight
}
# radix max at
# ----- ------
# 2 3 *---* Y=radix-1
# 3 8 \
# 4 15 \
# 5 24 * Y=0
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return (Math::NumSeq::PlanePathTurn::_turn_func_Turn4
(1,0, 1,1-$self->{'radix'}));
}
}
{ package Math::PlanePath::GrayCode;
# radix=2 TsF==Fs is always straight or left
sub _NumSeq_Turn_Right_max {
my ($self) = @_;
if ($self->{'radix'} == 2
&& ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'Fs')) {
return 0; # never right
}
return 1;
}
sub _NumSeq_Turn_Right_non_decreasing {
my ($self) = @_;
if ($self->{'radix'} == 2
&& ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'Fs')) {
return 1; # never right
}
return 0;
}
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
if ($self->{'radix'} == 2
&& ($self->{'apply_type'} eq 'TsF'
|| $self->{'apply_type'} eq 'Fs')) {
return 0; # never right
}
return -1;
}
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 2
&& ($self->{'apply_type'} eq 'sT' || $self->{'apply_type'} eq 'sF')
? 1 # never straight
: 0);
}
# ENHANCE-ME: check this is true
# PlanePathTurn planepath=GrayCode,apply_type=TsF,gray_type=reflected,radix=2, turn_type=SLR
# PlanePathTurn planepath=GrayCode,apply_type=Fs,gray_type=reflected,radix=2, turn_type=SLR
# match 1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1
# A039963 The period-doubling sequence A035263 repeated.
# A039963 ,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1
# Not quite, A039963 is OFFSET=0 vs first turn at N=1 here
# 'Math::PlanePath::GrayCode' =>
# {
# Left => 'A039963', # duplicated KochCurve
# LSR => 'A039963',
# },
# Koch characteristic of A003159 ending even zeros
# 'Math::PlanePath::GrayCode' =>
use constant _NumSeq_Turn_oeis_anum =>
{
do {
my $peano = Math::PlanePath::PeanoCurve
-> _NumSeq_Turn_oeis_anum -> {'radix=3'};
('apply_type=TsF,gray_type=reflected,radix=3' => $peano,
'apply_type=FsT,gray_type=reflected,radix=3' => $peano,
),
# OEIS-Other: A163536 planepath=GrayCode,apply_type=TsF,radix=3 turn_type=SLR
# OEIS-Other: A163536 planepath=GrayCode,apply_type=FsT,radix=3 turn_type=SLR
# OEIS-Other: A163537 planepath=GrayCode,apply_type=TsF,radix=3 turn_type=SRL
# OEIS-Other: A163537 planepath=GrayCode,apply_type=FsT,radix=3 turn_type=SRL
},
};
}
{ package Math::PlanePath::ImaginaryBase;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 2
? 1 # radix=2 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::ImaginaryHalf;
{
my %_NumSeq_Turn_SLR_min = (XYX => 1,
# XXY => 0,
YXX => 1,
# XnXY => 0,
XnYX => 1,
YXnX => 1,
);
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 2
&& $_NumSeq_Turn_SLR_min{$self->{'digit_order'}}
? 1
: 0);
}
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::CubicBase;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
{ package Math::PlanePath::Flowsnake;
# inherit from FlowsnakeCentres
}
{ package Math::PlanePath::FlowsnakeCentres;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::GosperIslands;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
{ package Math::PlanePath::KochCurve;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ Left => 'A035263', # OFFSET=1 matches N=1
# OEIS-Catalogue: A035263 planepath=KochCurve
SLR => 'A056832',
# OEIS-Catalogue: A056832 planepath=KochCurve turn_type=SLR
# A056832 All a(n) = 1 or 2; a(1) = 1; get next 2^k terms by repeating first 2^k terms and changing last element so sum of first 2^(k+1) terms is odd.
# A056832 ,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1
# Not quite, A096268 OFFSET=0 values 0,1,0,0,0,1
# whereas here N=1 first turn values 0,1,0,0,0,1
# Right => 'A096268', # morphism
},
};
}
{ package Math::PlanePath::KochPeaks;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
{ package Math::PlanePath::KochSnowflakes;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
{ package Math::PlanePath::KochSquareflakes;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
# { package Math::PlanePath::QuadricCurve;
# }
# { package Math::PlanePath::QuadricIslands;
# }
{ package Math::PlanePath::SierpinskiTriangle;
{
my %_NumSeq_Turn_Turn4_max = (triangular => 2.5,
left => 2.5,
right => 3,
diagonal => 2.5,
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return $_NumSeq_Turn_Turn4_max{$self->{'align'}};
}
}
}
{ package Math::PlanePath::SierpinskiArrowhead;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 0.5; # North-East diagonal
use constant _NumSeq_Turn_Turn4_max => 3.5; # South-East diagonal
}
{ package Math::PlanePath::SierpinskiArrowheadCentres;
use constant _NumSeq_Turn_Turn4_max => 3.5; # South-East diagonal
}
{ package Math::PlanePath::SierpinskiCurve;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
# use constant _NumSeq_Turn_oeis_anum =>
# { 'arms=1' =>
# {
# # Not quite, A039963 numbered OFFSET=0 whereas first turn at N=1 here
# Right => 'A039963', # duplicated KochCurve turns
# },
# },
# }
}
{ package Math::PlanePath::SierpinskiCurveStair;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1; # never straight
}
{ package Math::PlanePath::DragonCurve;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1; # left or right only
use constant _NumSeq_Turn_oeis_anum =>
{ 'arms=1' =>
{
'LSR' => 'A034947', # Jacobi symbol (-1/n)
# OEIS-Catalogue: A034947 planepath=DragonCurve turn_type=LSR
Turn4 => 'A099545', # (odd part of n) mod 4
# OEIS-Catalogue: A099545 planepath=DragonCurve turn_type=Turn4
# 'L1R0' => 'A014577', # left=1,right=0 OFFSET=0
# 'L0R1' => 'A014707', # left=0,right=1 OFFSET=0
# 'L1R2' => 'A014709', # left=1,right=2 OFFSET=0
# 'L1R3' => 'A099545', # left=1,right=3 OFFSET=1
# # Not quite, A014707 has OFFSET=0 cf first elem for N=1
# Left => 'A014707', # turn, 1=left,0=right
# # OEIS-Catalogue: A014707 planepath=DragonCurve
# # Not quite, A014577 has OFFSET=0 cf first elem for N=1
# Right => 'A014577', # turn, 0=left,1=right
# # OEIS-Catalogue: A014577 planepath=DragonCurve turn_type=Right
# Not quite A014709 OFFSET=0 vs first turn at N=1 here
# SLR => 'A014709'
# SRL => 'A014710',
},
};
}
{ package Math::PlanePath::DragonRounded;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 0.5;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
# { package Math::PlanePath::DragonMidpoint;
# }
{ package Math::PlanePath::AlternatePaper;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1; # left or right only
# A209615 is (-1)^e for each p^e prime=4k+3 or prime=2
# 3*3 mod 4 = 1 mod 4
# so picks out bit above lowest 1-bit, and factor -1 if an odd power-of-2
# which is the AlternatePaper turn formula
#
use constant _NumSeq_Turn_oeis_anum =>
{ 'arms=1' =>
{ LSR => 'A209615',
# OEIS-Catalogue: A209615 planepath=AlternatePaper turn_type=LSR
# # Not quite, A106665 has OFFSET=0 cf first here i=1
# 'Left' => 'A106665', # turn, 1=left,0=right
# # OEIS-Catalogue: A106665 planepath=AlternatePaper i_offset=1
},
};
}
{ package Math::PlanePath::GosperSide;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
# Suspect not in OEIS:
# Left or Right according to lowest non-zero ternary digit 1 or 2
#
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ Left => 'A137893', # turn, 1=left,0=right, OFFSET=1
SLR => 'A060236', # base-3 lowest non-zero digit 1=left,2=right
# OEIS-Catalogue: A137893 planepath=GosperSide
# OEIS-Other: A137893 planepath=TerdragonCurve
# OEIS-Catalogue: A060236 planepath=GosperSide turn_type=SLR
# OEIS-Other: A060236 planepath=TerdragonCurve turn_type=SLR
# cf A136442 - a(3n)=1, a(3n-1)=0, a(3n+1)=a(n)
# ternary lowest non-1 0->1 2->0
# Not quite, A080846 OFFSET=0 values 0,1,0,0,1 which are N=1 here
# Right => 'A080846',
# # OEIS-Catalogue: A080846 planepath=GosperSide turn_type=Right
# # OEIS-Other: A080846 planepath=TerdragonCurve turn_type=Right
# Or A189640 has extra initial 0.
},
};
}
{ package Math::PlanePath::TerdragonCurve;
# GosperSide and TerdragonCurve same turn sequence, by diff angles
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1;
use constant _NumSeq_Turn_Turn4_max => 3;
use constant _NumSeq_Turn_oeis_anum =>
{ 'arms=1' => Math::PlanePath::GosperSide->_NumSeq_Turn_oeis_anum->{''} };
}
{ package Math::PlanePath::TerdragonRounded;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 0.5;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::TerdragonMidpoint;
use constant _NumSeq_Turn_Turn4_max => 3;
}
{ package Math::PlanePath::R5DragonCurve;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1; # right or left turn always
# # Not quite, OFFSET=0 values 0,0,1,1,0
# # cf first turn here N=1 values 0,0,1,1,0
# # 'Math::PlanePath::R5DragonCurve' =>
# # { Right => 'A175337',
# # # OEIS-Catalogue: A175337 planepath=R5DragonCurve turn_type=Right
# # },
}
# { package Math::PlanePath::R5DragonMidpoint;
# }
{ package Math::PlanePath::CCurve;
# Not quite, A096268 OFFSET=1 vs first turn N=1 here
# Straight => 'A096268'
}
{ package Math::PlanePath::ComplexPlus;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'realpart'} == 1
? 1 # realpart=1 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::ComplexMinus;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'realpart'} == 1
? 1 # realpart=1 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::ComplexRevolving;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
}
{ package Math::PlanePath::Rows;
# if width==1 then always straight ahead
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'width'} > 1
? 1
: 0);
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return ($self->{'width'} > 1
? 0
: 1);
}
*_NumSeq_Turn_Right_max = \&_NumSeq_Turn_Left_max;
*_NumSeq_Turn_Right_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'width'} > 1
? -1
: 0);
}
sub _NumSeq_Turn_LSR_max {
my ($self) = @_;
return ($self->{'width'} > 1
? 1
: 0);
}
sub _NumSeq_Turn_LSR_non_decreasing {
my ($self) = @_;
return ($self->{'width'} > 1
? 0
: 1);
}
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'width'} == 2
? 1 # width=2 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
# 3---4 width=2
# \ N=2 turn4=1.5
# 1---2 N=3 turn4=2.5
sub _NumSeq_Turn_Turn4_min {
my ($self) = @_;
return ($self->{'width'} == 2
? 1.5 # at N=2
: 0); # otherwise has straight points
}
# *--------
# \---\
# *---------*
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'width'} <= 1
? 0 # width=1 always straight
: (Math::NumSeq::PlanePathTurn::_turn_func_Turn4
(1-$self->{'width'},1, 1,0))); # at row start
}
use constant _NumSeq_Turn_oeis_anum =>
{
'n_start=1,width=0' => # Rows width=0 is trivial X=N,Y=0
{ Left => 'A000004', # all-zeros
LSR => 'A000004', # all zeros, straight
# OEIS-Other: A000004 planepath=Rows,width=0
# OEIS-Other: A000004 planepath=Rows,width=0 turn_type=LSR
},
};
}
{ package Math::PlanePath::Columns;
# if height==1 then always straight ahead
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'height'} > 1 ? 1 : 0);
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return ($self->{'height'} > 1
? 0
: 1);
}
*_NumSeq_Turn_Right_max = \&_NumSeq_Turn_Left_max;
*_NumSeq_Turn_Right_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'height'} > 1 ? -1 : 0);
}
sub _NumSeq_Turn_LSR_max {
my ($self) = @_;
return ($self->{'height'} > 1 ? 1 : 0);
}
sub _NumSeq_Turn_LSR_non_decreasing {
my ($self) = @_;
return ($self->{'height'} > 1
? 0
: 1);
}
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'height'} == 2
? 1 # height=2 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
# 2 4 height=2
# | \ | N=2 turn4=2.5
# 1 3 N=3 turn4=1.5
sub _NumSeq_Turn_Turn4_min {
my ($self) = @_;
return ($self->{'height'} == 2
? 1.5 # at N=3
: 0); # otherwise has straight points
}
# *
# | \
# | |
# * *
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'height'} <= 1
? 0 # height=1 always straight
: (Math::NumSeq::PlanePathTurn::_turn_func_Turn4
(0,1, 1,1-$self->{'height'}))); # at column top
}
use constant _NumSeq_Turn_oeis_anum =>
{
'n_start=1,height=0' => # Columns height=0 is trivial X=N,Y=0
{ Left => 'A000004', # all-zeros
LSR => 'A000004', # all zeros, straight
# OEIS-Other: A000004 planepath=Columns,height=0
# OEIS-Other: A000004 planepath=Columns,height=0 turn_type=LSR
},
# 'n_start=-1,height=4' =>
# { Straight => 'A133872', # repeat 1,1,0,0 OFFSET=0
# NotStraight => 'A021913', # repeat 0,0,1,1 OFFSET=0
# # OEIS-Other: A133872 planepath=Columns,n_start=-1,height=4 turn_type=Straight
# # OEIS-Other: A021913 planepath=Columns,n_start=-1,height=4 turn_type=NotStraight
# },
};
}
{ package Math::PlanePath::Diagonals;
{
my %_NumSeq_Turn_Turn4_max
= (down => 2.5,
# at N=3 dx=-1,dy=+1 then dx=2,dy=-1
up => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-1,1, 2,-1));
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return $_NumSeq_Turn_Turn4_max{$self->{'direction'}};
}
}
use constant _NumSeq_Turn_oeis_anum =>
{ 'direction=down,n_start=0,x_start=0,y_start=0' =>
{ Left => 'A129184', # shift of triangle
srl => 'A156319', # triangle 1, 2, 0, 0, 0, ... in each row OFFSET=1
# OEIS-Catalogue: A129184 planepath=Diagonals,n_start=0
# OEIS-Catalogue: A156319 planepath=Diagonals,n_start=0 turn_type=srl
},
'direction=down,n_start=-1,x_start=0,y_start=0' =>
{ Right => 'A023531', # 1 at m(m+3)/2
# OEIS-Other: A023531 planepath=Diagonals,n_start=-1 turn_type=Right
},
'direction=up,n_start=0,x_start=0,y_start=0' =>
{ Right => 'A129184', # shift of triangle
SLR => 'A156319', # triangle 1, 2, 0, 0, 0, ... in each row OFFSET=1
# OEIS-Other: A129184 planepath=Diagonals,direction=up,n_start=0 turn_type=Right
# OEIS-Other: A156319 planepath=Diagonals,direction=up,n_start=0 turn_type=SLR
},
'direction=up,n_start=-1,x_start=0,y_start=0' =>
{ Left => 'A023531', # 1 at m(m+3)/2
# OEIS-Other: A023531 planepath=Diagonals,direction=up,n_start=-1
},
};
}
{ package Math::PlanePath::DiagonalsAlternating;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
{ package Math::PlanePath::DiagonalsOctant;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'direction'} eq 'down'
? 2.5 # N=3
: 3); # N=2
}
# # down is left or straight, but also right at N=2,3,4
# # up is straight or right, but also left at N=2,3,4
# 'Math::PlanePath::DiagonalsOctant,direction=down' =>
# { Left => square or pronic starting from 1
# },
# 'Math::PlanePath::DiagonalsOctant,direction=up' =>
# { Left => square or pronic starting from 1
# },
}
{ package Math::PlanePath::Staircase;
use constant _NumSeq_Turn_Turn4_min => 1;
use constant _NumSeq_Turn_Turn4_max => 3;
}
# { package Math::PlanePath::StaircaseAlternating;
# }
{ package Math::PlanePath::MPeaks;
use constant _NumSeq_Turn_Turn4_max => 3;
}
{ package Math::PlanePath::Corner;
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'wider'} == 0 ? 0 # wider=0 right or straight always
: 1);
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return ($self->{'wider'} == 0 ? 1 # wider=0 right or straight so left=0
: 0);
}
*_NumSeq_Turn_LSR_max = \&_NumSeq_Turn_Left_max;
use constant _NumSeq_Turn_Turn4_max => 3;
use constant _NumSeq_Turn_oeis_anum =>
{ 'wider=1,n_start=-1' =>
{ Left => 'A000007', # turn Left=1 at N=0 only
# catalogued only unless/until a better implementation
# OEIS-Catalogue: A000007 planepath=Corner,wider=1,n_start=-1
},
'wider=2,n_start=-1' =>
{ Left => 'A063524', # turn Left=1 at N=1 only
# catalogued only unless/until a better implementation
# OEIS-Catalogue: A063524 planepath=Corner,wider=2,n_start=-1
},
'wider=3,n_start=-1' =>
{ Left => 'A185012', # turn Left=1 at N=2 only
# catalogued only unless/until a better implementation
# OEIS-Catalogue: A185012 planepath=Corner,wider=3,n_start=-1
},
# A185013 Characteristic function of three.
# A185014 Characteristic function of four.
# A185015 Characteristic function of 5.
# A185016 Characteristic function of 6.
# A185017 Characteristic function of 7.
};
}
{ package Math::PlanePath::PyramidRows;
# if step==0 then always straight ahead
sub _NumSeq_Turn_Left_max {
my ($self) = @_;
return ($self->{'step'} > 0
? 1
: 0); # vertical only
}
sub _NumSeq_Turn_Left_non_decreasing {
my ($self) = @_;
return ($self->{'step'} > 0
? 0
: 1); # vertical only
}
*_NumSeq_Turn_Right_max = \&_NumSeq_Turn_Left_max;
*_NumSeq_Turn_Right_non_decreasing = \&_NumSeq_Turn_Left_non_decreasing;
sub _NumSeq_Turn_LSR_min {
my ($self) = @_;
return ($self->{'step'} > 0
? -1
: 0); # vertical only
}
sub _NumSeq_Turn_LSR_max {
my ($self) = @_;
return ($self->{'step'} > 0
? 1
: 0); # vertical only
}
sub _NumSeq_Turn_LSR_non_decreasing {
my ($self) = @_;
return ($self->{'step'} > 0
? 0
: 1); # vertical only
}
# *--* *---*
# | step=1 \ step=3
# * *
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'step'} == 0
? 0 # straight vertical only
# at N=2
: (Math::NumSeq::PlanePathTurn::_turn_func_Turn4
(- $self->{'left_slope'},1, 1,0)));
}
use constant _NumSeq_Turn_oeis_anum =>
{
# PyramidRows step=0 is trivial X=N,Y=0
do {
my $href= { Left => 'A000004', # all-zeros, OFFSET=0
LSR => 'A000004', # all zeros straight
};
('step=0,align=centre,n_start=1' => $href,
'step=0,align=right,n_start=1' => $href,
'step=0,align=left,n_start=1' => $href,
);
# OEIS-Other: A000004 planepath=PyramidRows,step=0
# OEIS-Other: A000004 planepath=PyramidRows,step=0 turn_type=LSR
# OEIS-Other: A000004 planepath=PyramidRows,step=0,align=right
# OEIS-Other: A000004 planepath=PyramidRows,step=0,align=left turn_type=LSR
},
# PyramidRows step=1
do {
my $href= { Left => 'A129184', # triangle 1s shift right
};
('step=1,align=centre,n_start=0' => $href,
'step=1,align=right,n_start=0' => $href,
'step=1,align=left,n_start=0' => $href,
);
# OEIS-Other: A129184 planepath=PyramidRows,step=1,n_start=0
# OEIS-Other: A129184 planepath=PyramidRows,step=1,align=right,n_start=0
# OEIS-Other: A129184 planepath=PyramidRows,step=1,align=left,n_start=0
},
do {
my $href= { Right => 'A023531', # 1 at n==m*(m+3)/2
};
('step=1,align=centre,n_start=-1' => $href,
'step=1,align=right,n_start=-1' => $href,
);
# OEIS-Other: A023531 planepath=PyramidRows,step=1,n_start=-1 turn_type=Right
# OEIS-Other: A023531 planepath=PyramidRows,step=1,align=right,n_start=-1 turn_type=Right
},
};
}
{ package Math::PlanePath::PyramidSides;
use constant _NumSeq_Turn_Left_max => 0; # right or straight
use constant _NumSeq_Turn_Left_non_decreasing => 1; # right or straight
use constant _NumSeq_Turn_LSR_max => 0; # right or straight
use constant _NumSeq_Turn_Turn4_max => 3; # at N=3
}
{ package Math::PlanePath::CellularRule;
sub _NumSeq_Turn_Left_increasing {
my ($self) = @_;
return (defined $self->{'rule'}
&& ($self->{'rule'} & 0x17) == 0 # single cell only
? 1
: 0);
}
*_NumSeq_Turn_Right_increasing = \&_NumSeq_Turn_Left_increasing;
sub _NumSeq_Turn_LSR_increasing {
my ($self) = @_;
return (defined $self->{'rule'}
&& ($self->{'rule'} & 0x17) == 0 # single cell only
? 1
: 0);
}
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return (($self->{'rule'} & 0x5F) == 0x0E # left line 2
|| ($self->{'rule'} & 0x5F) == 0x54 # right line 2
? 1 # never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
use constant _NumSeq_Turn_oeis_anum =>
{
do {
# right line 2, stair step
# |
# 3--1
# |
# 3--1 Turn4
# |
# *
my $href = { Turn4 => 'A176040', # 3,1 repeating OFFSET=0
};
('rule=84,n_start=-1' => $href,
'rule=116,n_start=-1' => $href,
'rule=212,n_start=-1' => $href,
'rule=244,n_start=-1' => $href)
# OEIS-Catalogue: A176040 planepath=CellularRule,rule=84,n_start=-1 turn_type=Turn4
# OEIS-Other: A176040 planepath=CellularRule,rule=116,n_start=-1 turn_type=Turn4
# OEIS-Other: A176040 planepath=CellularRule,rule=212,n_start=-1 turn_type=Turn4
# OEIS-Other: A176040 planepath=CellularRule,rule=244,n_start=-1 turn_type=Turn4
},
};
}
{ package Math::PlanePath::CellularRule::Line;
use constant _NumSeq_Turn_Left_max => 0; # straight ahead only
use constant _NumSeq_Turn_Left_non_decreasing => 1; # straight ahead only
use constant _NumSeq_Turn_Right_max => 0; # straight ahead only
use constant _NumSeq_Turn_Right_non_decreasing => 1; # straight ahead only
use constant _NumSeq_Turn_LSR_max => 0;
use constant _NumSeq_Turn_LSR_min => 0;
use constant _NumSeq_Turn_LSR_non_decreasing => 1; # straight ahead only
use constant _NumSeq_Turn_Turn4_max => 0;
use constant _NumSeq_Turn_Turn4_integer => 1;
}
{ package Math::PlanePath::CellularRule::OneTwo;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
# 5-6 5--6
# \ |
# 4 left rule=6 4 right rule=20
# ^----. N=2 turn4=2.5 / N=2 turn4=0.5
# 2--3 N=3 turn4=3.5 2--3 N=3 turn4=3
# \ N=4 turn4= |
# 1 1
sub _NumSeq_Turn_Turn4_min {
my ($self) = @_;
return ($self->{'align'} eq 'left'
? Math::NumSeq::PlanePathTurn::_turn_func_Turn4(1,0, -2,1) # N=3
: 0.5);
}
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'align'} eq 'left'
? Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-2,1, -1,1) # N=4
: 3);
}
use constant _NumSeq_Turn_oeis_anum =>
{ 'align=left,n_start=-1' =>
{ SRL => 'A131534', # repeat 1,2,1, 1,2,1, ... OFFSET=0
# OEIS-Catalogue: A131534 planepath=CellularRule,rule=6,n_start=-1 turn_type=SRL
# OEIS-Other: A131534 planepath=CellularRule,rule=38,n_start=-1 turn_type=SRL
# OEIS-Other: A131534 planepath=CellularRule,rule=134,n_start=-1 turn_type=SRL
# OEIS-Other: A131534 planepath=CellularRule,rule=166,n_start=-1 turn_type=SRL
},
'align=right,n_start=-1' =>
{ SRL => 'A130196', # repeat 1,2,2, 1,2,2, ... OFFSET=0
# OEIS-Catalogue: A130196 planepath=CellularRule,rule=20,n_start=-1 turn_type=SRL
# OEIS-Other: A130196 planepath=CellularRule,rule=52,n_start=-1 turn_type=SRL
# OEIS-Other: A130196 planepath=CellularRule,rule=148,n_start=-1 turn_type=SRL
# OEIS-Other: A130196 planepath=CellularRule,rule=180,n_start=-1 turn_type=SRL
},
};
}
{ package Math::PlanePath::CellularRule::OddSolid;
use constant _NumSeq_Turn_Turn4_max => 2.5; # at N=2
# R 0 0 L 1 0 0 2
# R 0 L 1 0 2
# R L 1 2
# . .
use constant _NumSeq_Turn_oeis_anum =>
{ 'n_start=0' =>
{ SRL => 'A156319', # triangle rows 1,2,0,0,0,0,...
# OEIS-Other: A156319 planepath=CellularRule,rule=50,n_start=0 turn_type=SRL
# OEIS-Other: A156319 planepath=CellularRule,rule=58,n_start=0 turn_type=SRL
# OEIS-Other: A156319 planepath=CellularRule,rule=250,n_start=0 turn_type=SRL
# OEIS-Other: A156319 planepath=CellularRule,rule=179,n_start=0 turn_type=SRL
},
};
}
{ package Math::PlanePath::CellularRule54;
use constant _NumSeq_Turn_Turn4_max => 2.5;
}
{ package Math::PlanePath::CellularRule57;
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return ($self->{'mirror'}
? 3.5
: Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-2,1, 2,0)); # N=2
}
}
{ package Math::PlanePath::CellularRule190;
use constant _NumSeq_Turn_Turn4_max => 2.5;
}
# { package Math::PlanePath::CoprimeColumns;
# }
# { package Math::PlanePath::DivisibleColumns;
# }
# { package Math::PlanePath::File;
# # File points from a disk file
# # FIXME: analyze points for min/max etc
# }
{ package Math::PlanePath::QuintetCurve;
use constant _NumSeq_Turn_Turn4_max => 3;
}
{ package Math::PlanePath::QuintetCentres;
use constant _NumSeq_Turn_Turn4_max => 3.5;
}
# { package Math::PlanePath::QuintetSide;
# PlanePathTurn planepath=QuintetSide, turn_type=SLR
# match 1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,1,2
# A060236 If n mod 3 = 0 then a(n)=a(n/3), otherwise a(n)=n mod 3.
# A060236 ,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,1,1,2,1,1,2,2,1,2,2,1,2,1,1,2,2,
# }
# { package Math::PlanePath::DekkingCurve;
# }
# { package Math::PlanePath::DekkingCentres;
# }
# { package Math::PlanePath::CincoCurve;
# }
{ package Math::PlanePath::CornerReplicate;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => # apparent minimum
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-1,0, -2,-1); # at N=11
use constant _NumSeq_Turn_Turn4_max => 3; # apparent maximum
}
{ package Math::PlanePath::SquareReplicate;
use constant _NumSeq_Turn_Turn4_max =>
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(2,1, 0,1); # at N=9
}
{ package Math::PlanePath::DigitGroups;
# radix=3 "11110222222" len many 1s, 2*len-2 many 2s gives ever-increasing
# radix=4 "1303333...3333" ever-increasing
}
{ package Math::PlanePath::FibonacciWordFractal;
use constant _NumSeq_Turn_oeis_anum =>
{ '' =>
{ SRL => 'A156596', # turns 0=straight,1=right,2=left
# OEIS-Catalogue: A156596 planepath=FibonacciWordFractal turn_type=SRL
# Not quite, A003849 OFFSET=0 vs first turn N=1 here
# Straight => 'A003849'
},
};
}
{ package Math::PlanePath::LTiling;
{
my %_NumSeq_Turn_SLR_min = (middle => 1,
upper => 1,
);
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($_NumSeq_Turn_SLR_min{$self->{'L_fill'}} || 0);
}
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
}
{ package Math::PlanePath::WythoffArray;
use constant _NumSeq_Turn_Turn4_max => # apparent maximum
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-2,3, 5,-4); # at N=12
}
{ package Math::PlanePath::PowerArray;
sub _NumSeq_Turn_SLR_min {
my ($self) = @_;
return ($self->{'radix'} == 3
? 1 # radix=3 never straight
: 0);
}
*_NumSeq_Turn_SRL_min = \&_NumSeq_Turn_SLR_min;
# Turn4 ...
#
# radix=2
# min i=2[10] 1.50000 px=1,py=0 dx=-1,dy=1 -1.000
# max i=3[11] 2.20000 px=-1,py=1 dx=2,dy=-1[10,-1] -2.000
#
# radix=3
# min i=130[11211] 0.00000 px=-1,py=58 dx=0,dy=1 0.000
# max i=67[2111] 3.98889 px=-1,py=30 dx=0,dy=1[0,1] 0.000
#
# radix=4
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=53[311] 3.98889 px=-1,py=30 dx=0,dy=1[0,1] 0.000
#
# radix=5
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=46[141] 3.98889 px=-1,py=29 dx=0,dy=1[0,1] 0.000
#
# radix=6
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=43[111] 3.98889 px=-1,py=30 dx=0,dy=1[0,1] 0.000
#
# radix=7
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=43[61] 3.98889 px=-1,py=31 dx=0,dy=1[0,1] 0.000
#
# radix=8
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=41[51] 3.98889 px=-1,py=31 dx=0,dy=1[0,1] 0.000
#
# radix=9
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=37[41] 3.98889 px=-1,py=29 dx=0,dy=1[0,1] 0.000
#
# radix=10
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=41[41] 3.98889 px=-1,py=33 dx=0,dy=1[0,1] 0.000
#
# radix=16
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=33[21] 3.98889 px=-1,py=29 dx=0,dy=1[0,1] 0.000
#
# radix=29
# min i=2[2] 0.00000 px=0,py=1 dx=0,dy=1 0.000
# max i=59[21] 3.98889 px=-1,py=55 dx=0,dy=1[0,1] 0.000
# use constant _NumSeq_oeis_anum =>
# # Not quite, A011765 0,0,0,1 repeating has OFFSET=1
# # cf n_start=1 is first turn at N=2
# # Left => 'A011765',
# # Right => 'A011765',
#
# # Not quite, A131534 has OFFSET=1 vs first turn at N=2 here
# # 'radix=3' =>
# # { SRL => 'A131534', # repeat 1,2,1, OFFSET=0
# # }
#
# # Not quite, A007877 has OFFSET=1 vs first turn at N=2 here
# # 'radix=4' =>
# # { SRL => 'A007877', # repeat 0,1,2,1
# # }
#
# # Not quite, 0,0,2,1,2 here vs A053796 0,2,1,2,0
# # 'radix=5' =>
# # { SRL => 'A053796', # repeat 0,2,1,2,0
# # }
# };
}
{ package Math::PlanePath::ToothpickTree;
{
my %_NumSeq_Turn_Turn4_max
= (wedge => 3, # at N=1 turn right
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return $_NumSeq_Turn_Turn4_max{$self->{'parts'}} || 4;
}
}
{
my %_NumSeq_Turn4_max_is_supremum
= (wedge => 0,
);
sub _NumSeq_Turn4_max_is_supremum {
my ($self) = @_;
my $ret = $_NumSeq_Turn4_max_is_supremum{$self->{'parts'}};
return (defined $ret ? $ret : 1);
}
}
}
{ package Math::PlanePath::ToothpickReplicate;
{
my %_NumSeq_Turn_Turn4_max
= ( # at N=16
'3' => Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-1,3, 0,1),
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return $_NumSeq_Turn_Turn4_max{$self->{'parts'}} || 3.5;
}
}
}
{ package Math::PlanePath::ToothpickUpist;
use constant _NumSeq_Turn_Turn4_max =>
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-2,1, 2,0); # at N=4
}
{ package Math::PlanePath::ToothpickSpiral;
use constant _NumSeq_Turn_SLR_min => 1; # never straight
use constant _NumSeq_Turn_SRL_min => 1; # never straight
use constant _NumSeq_Turn_Turn4_min => 1; # left or right always
}
{ package Math::PlanePath::LCornerReplicate;
# min i=63[333] 0.25556 px=1,py=0 dx=7,dy=3 2.333
use constant _NumSeq_Turn_Turn4_min =>
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(1,0, 7,3); # at N=63
# higher N=1333..3333[base4] loop 3.8, 2.8, 1.7888, 0.7888
# max i=8191[1333333] 3.80000 px=-1,py=0 dx=-38,dy=13[-212,31] -2.923
use constant _NumSeq_Turn_Turn4_max =>
Math::NumSeq::PlanePathTurn::_turn_func_Turn4(-1,0, -38,13); # at N=8191
}
{ package Math::PlanePath::LCornerTree;
# parts=3 maybe maximum
# max i=3107[300203] 3.98889 px=1,py=0 dx=66,dy=-1[1002,-1] -66.000
# LCornerTree,parts=diagonal-1 Turn4 values_max=4 vs saw_values_max=3 at i=27 (to i_end=801)
{
my %_NumSeq_Turn_Turn4_max
= (wedge => 3, # at N=14
'wedge+1' => 3, # at N=19
diagonal => 3, # at N=21
'diagonal-1' => 3, # at N=27
);
sub _NumSeq_Turn_Turn4_max {
my ($self) = @_;
return $_NumSeq_Turn_Turn4_max{$self->{'parts'}} || 4;
}
}
{
my %_NumSeq_Turn4_max_is_supremum
= (4 => 0, # apparently
);
sub _NumSeq_Turn4_max_is_supremum {
my ($self) = @_;
return $_NumSeq_Turn4_max_is_supremum{$self->{'parts'}};
}
}
}
1;
__END__
=for stopwords Ryde Math-PlanePath NumSeq PlanePath SquareSpiral ie LSR dX,dY dx1,dy1 dx2,dy2 dx1 dx2
=head1 NAME
Math::NumSeq::PlanePathTurn -- turn sequence from PlanePath module
=head1 SYNOPSIS
use Math::NumSeq::PlanePathTurn;
my $seq = Math::NumSeq::PlanePathTurn->new (planepath => 'DragonCurve',
turn_type => 'Left');
my ($i, $value) = $seq->next;
=head1 DESCRIPTION
This is a tie-in to present turns from a C module in the
form of a NumSeq sequence.
The C choices are
"Left" 1=left 0=right or straight
"Right" 1=right 0=left or straight
"LSR" 1=left 0=straight -1=right
"SLR" 0=straight 1=left 2=right
"SRL" 0=straight 1=right 2=left
In each case the value at i is the turn which occurs at N=i,
i+1
^
|
|
i-1 ---> i turn at i
first turn at i = n_start + 1
For multiple "arms" the turn follows that particular arm so it's i-arms, i,
i+arms. i values start C so i-arms is C,
the first N on the path. A single arm path beginning N=0 has its first turn
at i=1.
For "LSR", "SLR" and "SRL", straight means either straight ahead or
180-degree reversal, ie. the direction N to N+1 is along the same line as
N-1 to N was.
"Left" means to the left side of the N-1 to N line, not straight or right.
Similarly "Right" means to the right side of the N-1 to N line, not straight
or left.
=head1 FUNCTIONS
See L for behaviour common to all sequence classes.
=over 4
=item C<$seq = Math::NumSeq::PlanePathTurn-Enew (key=Evalue,...)>
Create and return a new sequence object. The options are
planepath string, name of a PlanePath module
planepath_object PlanePath object
turn_type string, as described above
C can be either the module part such as "SquareSpiral" or a
full class name "Math::PlanePath::SquareSpiral".
=item C<$value = $seq-Eith($i)>
Return the turn at N=$i in the PlanePath.
=item C<$bool = $seq-Epred($value)>
Return true if C<$value> occurs as a turn. Often this is merely the
possible turn values 1,0,-1, etc, but some spiral paths for example only go
left or straight in which case only 1 and 0 occur and C reflects
that.
=item C<$i = $seq-Ei_start()>
Return the first index C<$i> in the sequence. This is the position
C returns to.
This is C<$path-En_start() - $path-Earms_count()> from the
PlanePath object.
=back
=head1 FORMULAS
=head2 Turn Left or Right
A turn left or right is identified by considering the dX,dY at N-1 and at N.
N+1 *
| dx2,dy2
|
|
|
N *
/ dx1,dy1
/
/
N-1 *
With the two vectors dx1,dy1 and dx2,dy2 at a common origin, if the dx2,dy2
is above the dx1,dy1 line then it's a turn to the left, or below is a turn
to the right
dx2,dy2
*
| * dx1,dy1
| /
| /
|/
o
At dx2 the Y value of the dx1,dy1 vector is
cmpY = dx2 * dy1/dx1 if dx1 != 0
left if dy2 > cmpY
dy2 > dx2 * dy1/dx1
so dy2 * dx1 > dx2 * dy1
This comparison dy2*dx1 > dx2*dy1 works when dx1=0 too, ie. when dx1,dy1 is
vertical
left if dy2 * 0 > dx2 * dy1
0 > dx2*dy1
good, left if dx2 and dy1 opposite signs
So
dy2*dx1 > dx2*dy1 left
dy2*dx1 < dx2*dy1 right
dy2*dx1 = dx2*dy1 straight, including 180 degree reverse
=head1 SEE ALSO
L,
L,
L,
L
L has a C turn calculator
=head1 HOME PAGE
L
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/lib/Math/PlanePath/ 0002755 0001750 0001750 00000000000 12255673733 015231 5 ustar gg gg Math-PlanePath-113/lib/Math/PlanePath/TerdragonMidpoint.pm 0000644 0001750 0001750 00000057663 12250720133 021215 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# math-image --path=TerdragonMidpoint --lines --scale=40
#
# math-image --path=TerdragonMidpoint --all --output=numbers_dash --size=78x60
# math-image --path=TerdragonMidpoint,arms=6 --all --output=numbers_dash --size=78x60
package Math::PlanePath::TerdragonMidpoint;
use 5.004;
use strict;
use List::Util 'min'; # 'max'
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'digit_join_lowtohigh';
# uncomment this to run the ### lines
#use Smart::Comments;
use constant n_start => 0;
use constant parameter_info_array => [ { name => 'arms',
share_key => 'arms_6',
display => 'Arms',
type => 'integer',
minimum => 1,
maximum => 6,
default => 1,
width => 1,
description => 'Arms',
} ];
use constant sumabsxy_minimum => 2; # X=2,Y=0 or X=1,Y=1
sub rsquared_minimum {
my ($self) = @_;
return ($self->arms_count < 2
? 4 # 1 arm, minimum X=2,Y=0
: 2); # 2 or more arms, minimum X=1,Y=1
}
use constant dx_minimum => -2;
sub dx_maximum {
my ($self) = @_;
return ($self->{'arms'} == 1 ? 1 : 2);
}
use constant dy_minimum => -1;
use constant dy_maximum => 1;
use constant absdx_minimum => 1;
use constant dsumxy_minimum => -2; # diagonals
use constant dsumxy_maximum => 2;
use constant ddiffxy_minimum => -2;
use constant ddiffxy_maximum => 2;
# arms=1 curve goes at 60,180,300 degrees
# arms=2 second +60 to 120,240,0 degrees
# so when arms==1 dir minimum is 60 degrees North-East
#
sub dir_minimum_dxdy {
my ($self) = @_;
return ($self->{'arms'} == 1
? (1,1) # North-East
: (1,0)); # East
}
use constant dir_maximum_dxdy => (1,-1); # South-East
#------------------------------------------------------------------------------
# Not quite.
# # all even points when arms==3
# use Math::PlanePath::TerdragonCurve;
# *xy_is_visited = \&Math::PlanePath::TerdragonCurve::xy_is_visited;
sub new {
my $self = shift->SUPER::new(@_);
$self->{'arms'} = max(1, min(6, $self->{'arms'} || 1));
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### TerdragonMidpoint n_to_xy(): $n
if ($n < 0) { return; }
if (is_infinite($n)) { return ($n, $n); }
{
my $int = int($n);
if ($n != $int) {
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+$self->{'arms'});
my $frac = $n - $int; # inherit possible BigFloat
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int; # BigFloat int() gives BigInt, use that
}
# ENHANCE-ME: own code ...
#
require Math::PlanePath::TerdragonCurve;
my ($x1,$y1) = $self->Math::PlanePath::TerdragonCurve::n_to_xy($n);
my ($x2,$y2) = $self->Math::PlanePath::TerdragonCurve::n_to_xy($n+$self->{'arms'});
# dx = x2-x1
# X = 2 * (x1 + dx/2)
# = 2 * (x1 + x2/2 - x1/2)
# = 2 * (x1/2 + x2/2)
# = x1+x2
return ($x1+$x2,
$y1+$y2);
}
# sub n_to_xy {
# my ($self, $n) = @_;
# ### TerdragonMidpoint n_to_xy(): $n
#
# if ($n < 0) { return; }
# if (is_infinite($n)) { return ($n, $n); }
#
# my $frac;
# {
# my $int = int($n);
# $frac = $n - $int; # inherit possible BigFloat
# $n = $int; # BigFloat int() gives BigInt, use that
# }
#
# my $zero = ($n * 0); # inherit bignum 0
#
# ($n, my $rot) = _divrem ($n, $self->{'arms'});
#
# # ENHANCE-ME: sx,sy just from len,len
# my @digits;
# my @sx;
# my @sy;
# {
# my $sx = $zero + 1;
# my $sy = -$sx;
# while ($n) {
# push @digits, ($n % 2);
# push @sx, $sx;
# push @sy, $sy;
# $n = int($n/2);
#
# # (sx,sy) + rot+90(sx,sy)
# ($sx,$sy) = ($sx - $sy,
# $sy + $sx);
# }
# }
#
# ### @digits
# my $rev = 0;
# my $x = $zero;
# my $y = $zero;
# my $above_low_zero = 0;
#
# for (my $i = $#digits; $i >= 0; $i--) { # high to low
# my $digit = $digits[$i];
# my $sx = $sx[$i];
# my $sy = $sy[$i];
# ### at: "$x,$y $digit side $sx,$sy"
# ### $rot
#
# if ($rot & 2) {
# $sx = -$sx;
# $sy = -$sy;
# }
# if ($rot & 1) {
# ($sx,$sy) = (-$sy,$sx);
# }
# ### rotated side: "$sx,$sy"
#
# if ($rev) {
# if ($digit) {
# $x += -$sy;
# $y += $sx;
# ### rev add to: "$x,$y next is still rev"
# } else {
# $above_low_zero = $digits[$i+1];
# $rot ++;
# $rev = 0;
# ### rev rot, next is no rev ...
# }
# } else {
# if ($digit) {
# $rot ++;
# $x += $sx;
# $y += $sy;
# $rev = 1;
# ### plain add to: "$x,$y next is rev"
# } else {
# $above_low_zero = $digits[$i+1];
# }
# }
# }
#
# # Digit above the low zero is the direction of the next turn, 0 for left,
# # 1 for right.
# #
# ### final: "$x,$y rot=$rot above_low_zero=".($above_low_zero||0)
#
# if ($rot & 2) {
# $frac = -$frac; # rotate 180
# $x -= 1;
# }
# if (($rot+1) & 2) {
# # rot 1 or 2
# $y += 1;
# }
# if (!($rot & 1) && $above_low_zero) {
# $frac = -$frac;
# }
# $above_low_zero ^= ($rot & 1);
# if ($above_low_zero) {
# $y = $frac + $y;
# } else {
# $x = $frac + $x;
# }
#
# ### rotated offset: "$x_offset,$y_offset return $x,$y"
# return ($x,$y);
# }
# w^2 = -1+w
# c = (X-Y)/2 x=2c+d
# d = Y y=d
# (c+dw)/(w+1)
# = (c+dw)*(2-w)/3
# = (2c-cw + 2dw-dw^2) / 3
# = (2c-cw + 2dw-d(w-1)) / 3
# = (2c-cw + 2dw-dw+d)) / 3
# = (2c+d + w(-c + 2d-d)) / 3
# = (2c+d + w(d-c)) / 3
#
# = (x-y+y + w(y - (x-y)/2)) / 3
# = (x + w((2y-x+y)/2)) / 3
# = (x + w((3y-x)/2)) / 3
# then
# xq = 2c+d
# = (2x + (3y-x)/2 ) / 3
# = (4x + 3y-x)/6
# = (3x+3y)/6
# = (x+y)/2
# yq = d = (3y-x)/6
#
# (-1+5w)(2-w) x=2*-1+5=3,y=5
# = -2+w+10w-5w^2
# = -2+11w-5(w-1)
# = -2+11w-5w+5
# = 3+6w -> 1+2w
# c=2*-1+5=3 d=-1+5=4
# x=2*1+2=4 y=3
#
# (w+1)*(2-w)
# = 2w-w^2+2-w
# = 2w-(w-1)+2-w
# = 2w-w+1+2-w
# = 3 -> 1 x=2
#
# 3w*(2-w) x=3,y=3 div x=3,y(3+3)/2=3
# = 6w-3w^2
# = 6w-3(w-1)
# = 6w-3w+3
# = 3w+3 -> w+1 x=3,y=1
#
# (w+1)(w+1)
# = w^2+2w+1
# = w-1+2w+1
# = 3w
#
#
# x=3,y=3 (x+y)/2=3
# X=-3 -2 -1 0 1 2 3
my @yx_to_arm = ([9, 9, 9, 4, 9, 9, 9], # Y=-2
[3, 9, 9, 9, 9, 9, 5], # Y=-1
[9, 9, 9, 9, 9, 9, 9], # Y=0
[2, 9, 9, 9, 9, 9, 0], # Y=1
[9, 9, 9, 1, 9, 9, 9], # Y= 2
);
# my @yx_to_dxdy = (undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
# 1,1, 0,0, -1,-1, -2,0, 0,0, 2,0,
# undef,undef, 1,-1, undef,undef, -1,1, undef,undef, 0,0,
# 0,0, 2,0, 1,1, 0,0, -1,-1, -2,0,
# undef,undef, 0,0, undef,undef, 1,-1, undef,undef, -1,1,
# -1,-1, -2,0, 0,0, 2,0, 1,1, 0,0,
# );
my @yx_to_dxdy # 12 each row
= (undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
0,0, undef,undef, undef,undef, undef,undef, -1,-1, undef,undef,
undef,undef, undef,undef, 1,1, undef,undef, undef,undef, undef,undef,
undef,undef, 2,0, undef,undef, 0,0, undef,undef, -2,0,
undef,undef, -1,1, undef,undef, 0,0, undef,undef, 1,-1,
);
my @x_to_digit = (1, 2, 0); # digit = X+1 mod 3
sub xy_to_n {
my ($self, $x, $y) = @_;
### TerdragonMidpoint xy_to_n(): "$x, $y"
$x = round_nearest($x);
$y = round_nearest($y);
if (is_infinite($x)) {
return $x; # infinity
}
if (is_infinite($y)) {
return $y; # infinity
}
my $zero = ($x * 0 * $y); # inherit bignum 0
my @ndigits; # low to high;
for (;;) {
my $digit = $x_to_digit[$x%3];
my $k = 2*(12*($y%12) + ($x%12));
my $dx = $yx_to_dxdy[$k++];
if (! defined $dx) {
### not a visited point ...
return undef;
}
### at: "$x,$y (k=$k) n=$n digit=$digit k=$k offset=$yx_to_dxdy[$k-1],$yx_to_dxdy[$k] to ".($x+$yx_to_dxdy[$k-1]).",".($y+$yx_to_dxdy[$k])
push @ndigits, $digit;
$x += $dx;
$y += $yx_to_dxdy[$k];
last if ($x <= 3 && $x >= -3 && $y <= 2 && $y >= -2);
### assert: ($x+$y) % 2 == 0
### assert: $x % 3 == 0
### assert: (3 * $y - $x) % 6 == 0
($x,$y) = (($x+$y)/2, # divide w+1
($y-$x/3)/2);
### divide down to: "$x,$y"
}
### final: "xy=$x,$y"
my $arm = $yx_to_arm[$y+2][$x+3] || 0; # 0 to 5
### $arm
my $arms_count = $self->arms_count;
if ($arm >= $arms_count) {
return undef;
}
if ($arm & 1) {
### flip ...
@ndigits = map {2-$_} @ndigits;
}
return digit_join_lowtohigh(\@ndigits, 3, $zero) * $arms_count + $arm;
}
# quarter size of TerdragonCurve
#
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### TerdragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
my $xmax = int(max(abs($x1),abs($x2)));
my $ymax = int(max(abs($y1),abs($y2)));
return (0,
int (($xmax*$xmax + 3*$ymax*$ymax + 1)
/ 2)
* $self->{'arms'});
}
1;
__END__
# 72----66----60----54
# \ /
# 55 78 48
# / \ \ /
# 61 49 96----90----84 42
# / \ /
# 67 43 19 36
# / \ / \ /
# 73----79----85 37 25 13 30----24----18
# / \ / \ /
# 91 31 7 12
# / \ /
# 97 20----14-----8-----2 1 6 35----41----47--...
# \ / \
# 26 3 0 29
# \ / \
# ...-44----38----32 9 4 5----11----17----23 100
# / \ /
# 15 10 34 94
# / \ / \ /
# 21----27----33 16 28 40 88----82----76
# / \ / \ /
# 39 22 46 70
# / \ /
# 45 87----93----99 52 64
# / \ \ /
# 51 81 58
# / \
# 57----63----69----75
=for stopwords eg Ryde Terdragon Math-PlanePath Nlevel Davis Knuth et al terdragon ie Xadj Yadj
=head1 NAME
Math::PlanePath::TerdragonMidpoint -- dragon curve midpoints
=head1 SYNOPSIS
use Math::PlanePath::TerdragonMidpoint;
my $path = Math::PlanePath::TerdragonMidpoint->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
XXThis is midpoints of an integer version of the
terdragon curve by Davis and Knuth.
30----29----28----27 13
\ /
31 26 12
\ /
36----35----34----33----32 25 11
\ /
37 41 24 10
\ / \ /
38 40 42 23----22----21 9
\ / \ /
39 43 20 8
\ /
48----47----46----45----44 19 12----11----10-----9 7
\ / \ /
49 18 13 8 6
\ / \ /
...---50 17----16----15----14 7 5
/
6 4
/
5-----4-----3 3
/
2 2
/
1 1
/
0 <- Y=0
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
-12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X=0 1 2 3 4 5 ...
The points are the middle of each edge of a double-size C.
...
\
6 -----8----- double size
\ TerdragonCurve
\ giving midpoints
5 7
\
\
4 -----6---- _
\ / \
\ / \
3 5 4 3
\ / \
\_/ \
2 _----2-----
\
\
1 1
\
\
Y=0 -> +-----0-----.
^
X=0 1 2 3 4 5 6
For example in the C N=3 to N=4 is X=3,Y=1 to X=2,Y=2 and
that's doubled out here to X=6,Y=2 and X=4,Y=4 then the midpoint of those
positions is X=5,Y=3 for N=3 in the C.
The result is integer X,Y coordinates on every second point per
L, but visiting only 3 of every 4 such
triangular points, which in turn is 3 of 8 all integer X,Y points. The
points used are a pattern of alternate rows with 1 of 2 points and 1 of 4
points. For example the Y=7 row is 1 of 2 and the Y=8 row is 1 of 4.
Notice the pattern is the same when turned by 60 degrees.
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
=head2 Arms
Multiple copies of the curve can be selected, each advancing successively.
Like the main C the midpoint curve covers 1/6 of the plane
and 6 arms rotated by 60, 120, 180, 240 and 300 degrees mesh together
perfectly. With 6 arms all the alternating "1of2" and "1of4" points
described above are visited.
C 6> begins as follows. N=0,6,12,18,etc is the first arm (like
the single curve above), then N=1,7,13,19 the second copy rotated 60
degrees, N=2,8,14,20 the third rotated 120, etc.
arms=>6 ...
/
... 42
\ /
43 19 36
\ / \ /
37 25 13 30----24----18
\ / \ /
31 7 12
\ /
20----14-----8-----2 1 6 35----41----47-..
\ / \
26 3 . 0 29
\ / \
..-44----38----32 9 4 5----11----17----23
/ \
15 10 34
/ \ / \
21----27----33 16 28 40
/ \ / \
39 22 46
/ \
45 ...
/
...
=head1 FUNCTIONS
See L for behaviour common to all path classes.
=over 4
=item C<$path = Math::PlanePath::TerdragonMidpoint-Enew ()>
Create and return a new path object.
=item C<($x,$y) = $path-En_to_xy ($n)>
Return the X,Y coordinates of point number C<$n> on the path. Points begin
at 0 and if C<$n E 0> then the return is an empty list.
Fractional positions give an X,Y position along a straight line between the
integer positions.
=item C<$n = $path-En_start()>
Return 0, the first N in the path.
=back
=head1 FORMULAS
=head2 X,Y to N
An X,Y point can be turned into N by dividing out digits of a complex base
w+1 where
w = 1/2 + i * sqrt(3)/2 w^2 w
= 6th root of unity \ /
\ /
w^3=-1 -----o------ w^0=1
/ \
/ \
w^4 w^5
At each step the low ternary digit is formed from X,Y and an adjustment
applied to move X,Y onto a multiple of w+1 ready to divide out w+1.
In the N points above it can be seen that each group of three N values make
a straight line, such as N=0,1,2, or N=3,4,5 etc. The adjustment moves the
two ends N=0mod3 or N=2mod3 to the centre N=1mod3. The centre N=1mod3
position is always a multiple of w+1.
The angles and positions for the N triples follow a 12-point pattern as
follows, where each / \ or - is a point on the path (any arm).
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
\ / / \ / / \ / / \ / / \
- \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
/ \ / / \ / / \ / / \ /
\ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
In the current code a 12x12 table is used, indexed by X mod 12 and Y mod 12.
With Xadj and Yadj from there
Ndigit = (X + 1) mod 3 # N digits low to high
Xm = X + Xadj[X mod 12, Y mod 12]
Ym = Y + Yadj[X mod 12, Y mod 12]
new X,Y = (Xm,Ym) / (w+1)
= (Xm,Ym) * (2-w) / 3
= ((Xm+Ym)/2, (Ym-(Xm/3))/2)
Is there a good aX+bY mod 12 or mod 24 for a smaller table? Maybe X+3Y like
the digit? Taking C=(X-Y)/2 in triangular coordinate style can reduce the
table to 6x6.
Points not reached by the curve (ie. not the 3 of 4 triangular or 3 of 8
rectangular described above) can be detected with C or suitably
tagged entries in the adjustment table.
The X,Y reduction stops at the midpoint of the first triple of the
originating arm. So X=3,Y=1 which is N=1 for the first arm, and that point
rotated by 60,120,180,240,300 degrees for the others. If only some of the
arms are of interest then reaching one of the others means the original X,Y
was outside the desired region.
Arm X,Y Endpoint
--- ------------
0 3,1
1 0,2
2 -3,1
3 -3,-1
4 0,-2
5 3,-1
For the odd arms 1,3,5 each digit of N must be flipped 2-digit so 0,1,2
becomes 2,1,0,
if arm odd
then N = 3**numdigits - 1 - N
=head1 SEE ALSO
L,
L,
L
L,
L
=head1 HOME PAGE
L
=head1 LICENSE
Copyright 2011, 2012, 2013 Kevin Ryde
This file is part of Math-PlanePath.
Math-PlanePath 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, or (at your option) any later
version.
Math-PlanePath 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
Math-PlanePath. If not, see .
=cut
Math-PlanePath-113/lib/Math/PlanePath/FactorRationals.pm 0000644 0001750 0001750 00000064523 12250720134 020651 0 ustar gg gg # Copyright 2011, 2012, 2013 Kevin Ryde
# This file is part of Math-PlanePath.
#
# Math-PlanePath 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, or (at your option) any later
# version.
#
# Math-PlanePath 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 Math-PlanePath. If not, see .
# Multiples of prime make grid.
# [13] L. S. Johnston, Denumerability of the rational number system, Amer. Math. Monthly, 55 (Feb.
# 1948), no. 2, 65-70.
# www.jstor.org/stable/2305738
# prime factors q1,..qk of n
# f(m/n) = m^2*n^2/ (q1q2...qk)
# Kevin McCrimmon, 1960
#
# integer prod p[i]^a[i] -> rational prod p[i]^b[i]
# b[i] = a[2i-1] if a[2i-1]!=0
# b[1]=a[1], b[2]=a[3], b[3]=a[5]
# b[i] = -a[2k] if a[2i-1]=0 and is kth such
#
# b[i] = f(a[i]) where f(n) = (-1)^(n+1) * floor((n+1)/2)
# f(0) = 0
# f(1) = 1
# f(2) = -1
# f(3) = 2
# f(4) = -2
# Gerald Freilich, 1965
#
# f(n) = n/2 if n even n>=0
# = -(n+1)/2 if n odd n>0
# f(0)=0/2 = 0
# f(1)=-(1+1)/2 = -1
# f(2)=2/2 = 1
# f(3)=-(3+1)/2 = -2
# f(4)=4/2 = 2
# Yoram Sagher, "Counting the rationals", American Math Monthly, Nov 1989,
# page 823. http://www.jstor.org/stable/2324846
#
# m = p1^e1.p2^e2...
# n = q1^f1.q2^f2...
# f(m/n) = p1^2e1.p2^2e2... . q1^(2f1-1).q2^(2f2-1)...
# so 0 -> 0 0 -> 0
# num 1 -> 2 1 -> -1
# 2 -> 4 2 -> 1
# den -1 1 -> 2*1-1 = 1 3 -> -2
# -2 2 -> 2*2-1 = 3 4 -> 2
# Umberto Cerruti, "Ordinare i razionali Gli alberi di Keplero e di
# Calkin-Wilf", following T.J. Heard
# B(2k)=-k even=negative and zero
# B(2k-1)=k odd=positive
# which is Y/X invert
# B(0 =2*0) = 0
# B(1 =2*1-1) = 1
# B(2 =2*1) = -1
# B(3 =2*2-1) = 2
# B(4 =2*2) = -2
package Math::PlanePath::FactorRationals;
use 5.004;
use strict;
use Carp;
use List::Util 'min';
#use List::Util 'max';
*max = \&Math::PlanePath::_max;
use vars '$VERSION', '@ISA';
$VERSION = 113;
use Math::PlanePath;
@ISA = ('Math::PlanePath');
use Math::PlanePath::Base::Generic
'is_infinite',
'round_nearest';
use Math::PlanePath::Base::Digits
'digit_join_lowtohigh';
use Math::PlanePath::CoprimeColumns;
*_coprime = \&Math::PlanePath::CoprimeColumns::_coprime;
# uncomment this to run the ### lines
# use Smart::Comments;
# Not yet.
use constant parameter_info_array =>
[ { name => 'factor_coding',
display => 'Sign Encoding',
type => 'enum',
default => 'even/odd',
choices => ['even/odd','odd/even',
'negabinary','revbinary',
],
choices_display => ['Even/Odd','Odd/Even',
'Negabinary','Revbinary',
],
},
];
use constant class_x_negative => 0;
use constant class_y_negative => 0;
use constant x_minimum => 1;
use constant y_minimum => 1;
use constant gcdxy_maximum => 1; # no common factor
use constant absdy_minimum => 1;
# factor_coding=even/odd
# factor_coding=odd/even
# dir_minimum_dxdy() suspect dir approaches 0.
# Eg. N=5324 = 2^2.11^3 dx=3,dy=92 0.97925
# N=642735 = 3^5.23^2 dX=45 dY=4 Dir4=0.05644
# 642736 = 2^4.17^2.139
# dir_maximum_dxdy() suspect approaches 360 degrees
# use constant dir_maximum_dxdy => (0,0); # the default
#
# factor_coding=negabinary
# dir_minimum_dxdy() = East 1,0 at N=1
# dir_maximum_dxdy() believe approaches 360 degrees
# Eg. N=40=2^3.5 X=5, Y=2
# N=41=41 X=41, Y=1
# N=multiple 8 and solitary primes, followed by N+1=prime is dX=big, dY=-1
#
# factor_coding=revbinary
# dir_maximum_dxdy() approaches 360 degrees dY=-1, dX=big
# Eg. N=7208=2^3*17*53 X=17*53 Y=2
# N=7209=3^4*89 X=3^4*89 Y=1
# dX=6308 dY=-1
#------------------------------------------------------------------------------
# even/odd
# $n>=0, return a positive if even or negative if odd
# $n==0 return 0
# $n==1 return -1
# $n==2 return +1
# $n==3 return -2
# $n==4 return +2
sub _pos_to_pn__even_odd {
my ($n) = @_;
return ($n % 2 ? -1-$n : $n) / 2;
}
# # $n is positive or negative, return even for positive or odd for negative.
# # $n==0 return 0
# # $n==-1 return 1
# # $n==+1 return 2
# # $n==-2 return 3
# # $n==+2 return 4
# sub _pn_to_pos__even_odd {
# my ($n) = @_;
# return ($n >= 0 ? 2*$n : -1-2*$n);
# }
#------------------------------------------------------------------------------
# odd/even
# $n>=0, return a positive if even or negative if odd
# $n==0 return 0
# $n==1 return +1
# $n==2 return -1
# $n==3 return +2
# $n==4 return -2
sub _pos_to_pn__odd_even {
my ($n) = @_;
return ($n % 2 ? $n+1 : -$n) / 2;
}
# # $n is positive or negative, return odd for positive or even for negative.
# # $n==0 return 0
# # $n==+1 return 1
# # $n==-1 return 2
# # $n==+2 return 3
# # $n==-2 return 4
# sub _pn_to_pos__odd_even {
# my ($n) = @_;
# return ($n <= 0 ? -2*$n : 2*$n-1);
# }
#------------------------------------------------------------------------------
# negabinary
sub _pn_to_pos__negabinary {
my ($n) = @_;
my @bits;
while ($n) {
my $bit = ($n % 2);
push @bits, $bit;
$n -= $bit;
$n /= 2;
$n = -$n;
}
return digit_join_lowtohigh(\@bits, 2,
$n); # zero
}
sub _pos_to_pn__negabinary {
my ($n) = @_;
return (($n & 0x55555555) - ($n & 0xAAAAAAAA));
}
#------------------------------------------------------------------------------
# revbinary
# A065620 pos -> pn
# A065621 pn(+ve) -> pos
# A048724 pn(-ve) -> pos n XOR 2n
# A048725 A048724 twice
# cf
# A073122 minimizing by taking +/- powers cf A072219 A072339
# rev = 2^e0 - 2^e1 + 2^e2 - 2^e3 + ... + (-1)^t*2^et
# 0 <= e0 < e1 < e2 ...
sub _pos_to_pn__revbinary {
my ($n) = @_;
my $sign = 1;
my $ret = 0;
for (my $bit = 1; $bit <= $n; $bit *= 2) {
if ($n & $bit) {
$ret += $bit*$sign;
$sign = -$sign;
}
}
return $ret;
}
sub _pn_to_pos__revbinary {
my ($n) = @_;
my @bits;
while ($n) {
my $bit = ($n % 2);
push @bits, $bit;
$n -= $bit;
$n /= 2;
if ($bit) {
$n = -$n;
}
}
return digit_join_lowtohigh(\@bits, 2,
$n); # zero
}
#------------------------------------------------------------------------------
my %factor_coding__pos_to_pn = ('even/odd' => \&_pos_to_pn__even_odd,
'odd/even' => \&_pos_to_pn__odd_even,
negabinary => \&_pos_to_pn__negabinary,
revbinary => \&_pos_to_pn__revbinary,
);
my %factor_coding__pn_to_pos = (# 'even/odd' => \&_pn_to_pos__even_odd,
# 'odd/even' => \&_pn_to_pos__odd_even,
negabinary => \&_pn_to_pos__negabinary,
revbinary => \&_pn_to_pos__revbinary,
);
sub new {
my $self = shift->SUPER::new(@_);
my $factor_coding = ($self->{'factor_coding'} ||= 'even/odd');
$factor_coding__pos_to_pn{$factor_coding}
or croak "Unrecognised factor_coding: ",$factor_coding;
return $self;
}
sub n_to_xy {
my ($self, $n) = @_;
### FactorRationals n_to_xy(): "$n"
if ($n < 1) { return; }
if (is_infinite($n)) { return ($n,$n); }
# what to do for fractional $n?
{
my $int = int($n);
if ($n != $int) {
### frac ...
my $frac = $n - $int; # inherit possible BigFloat/BigRat
my ($x1,$y1) = $self->n_to_xy($int);
my ($x2,$y2) = $self->n_to_xy($int+1);
my $dx = $x2-$x1;
my $dy = $y2-$y1;
return ($frac*$dx + $x1, $frac*$dy + $y1);
}
$n = $int;
}
my $zero = $n * 0;
my $pos_to_pn = $factor_coding__pos_to_pn{$self->{'factor_coding'}};
my $x = my $y = ($n * 0) + 1; # inherit bignum 1
my ($limit,$overflow) = _limit($n);
### $limit
my $divisor = 2;
my $dstep = 1;
while ($divisor <= $limit) {
if (($n % $divisor) == 0) {
my $count = 0;
for (;;) {
$count++;
$n /= $divisor;
if ($n % $divisor) {
my $pn = &$pos_to_pn($count);
### $count
### $pn
my $pow = ($divisor+$zero) ** abs($pn);
if ($pn >= 0) {
$x *= $pow;
} else {
$y *= $pow;
}
last;
}
}
($limit,$overflow) = _limit($n);
### $limit
}
$divisor += $dstep;
$dstep = 2;
}
if ($overflow) {
### n too big ...
return;
}
### remaining $n is prime, count=1: "n=$n"
my $pn = &$pos_to_pn(1);
### $pn
my $pow = $n ** abs($pn);
if ($pn >= 0) {
$x *= $pow;
} else {
$y *= $pow;
}
### result: "$x, $y"
return ($x, $y);
}
sub xy_to_n {
my ($self, $x, $y) = @_;
$x = round_nearest ($x);
$y = round_nearest ($y);
### FactorRationals xy_to_n(): "x=$x y=$y"
if ($x < 1 || $y < 1) {
return undef; # negatives and -infinity
}
if (is_infinite($x)) { return $x; } # +infinity or nan
if (is_infinite($y)) { return $y; } # +infinity or nan
if ($self->{'factor_coding'} eq 'negabinary'
|| $self->{'factor_coding'} eq 'revbinary') {
### negabinary or revbinary ...
my $pn_to_pos = $factor_coding__pn_to_pos{$self->{'factor_coding'}};
my $n = 1;
my $zero = $x * 0 * $y;
# Factorize both $x and $y and apply their pn_to_pos encoded powers to
# make $n. A common factor between $x and $y is noticed if $divisor
# divides both.
my ($limit,$overflow) = _limit(max($x,$y));
my $dstep = 1;
for (my $divisor = 2; $divisor <= $limit; $divisor += $dstep, $dstep=2) {
my $count = 0;
if ($x % $divisor == 0) {
if ($y % $divisor == 0) {
return undef; # common factor
}
while ($x % $divisor == 0) {
$count++;
$x /= $divisor; # mutate loop variable
}
} elsif ($y % $divisor == 0) {
while ($y % $divisor == 0) {
$count--;
$y /= $divisor; # mutate loop variable
}
} else {
next;
}
# Here $count > 0 if from $x or $count < 0 if from $y.
### $count
### pn: &$pn_to_pos($count)
$count = &$pn_to_pos($count);
$n *= ($divisor+$zero) ** $count;
# new search limit, perhaps smaller than before
($limit,$overflow) = _limit(max($x,$y));
}
if ($overflow) {
### x,y too big to find all primes ...
return undef;
}
# Here $x and $y are primes.
if ($x > 1 && $x == $y) {
### common factor final remaining prime x,y ...
return undef;
}
# $x is power p^1 which is negabinary=1 or revbinary=1 so multiply into
# $n. $y is power p^-1 and -1 is negabinary=3 so cube and multiply into
# $n.
$n *= $x;
$n *= $y*$y*$y;
return $n;
} else {
### assert: $self->{'factor_coding'} eq 'even/odd' || $self->{'factor_coding'} eq 'odd/even'
if ($self->{'factor_coding'} eq 'odd/even') {
($x,$y) = ($y,$x);
}
# Factorize $y so as to make an odd power of its primes. Only need to
# divide out one copy of each prime, but by dividing out them all the
# $limit to search up to is reduced, usually by a lot.
#
# $ymult is $y with one copy of each prime factor divided out.
# $ychop is $y with all primes divided out as they're found.
# $y itself is unchanged.
#
my $ychop = my $ymult = $y;
my ($limit,$overflow) = _limit($ychop);
my $dstep = 1;
for (my $divisor = 2; $divisor <= $limit; $divisor += $dstep, $dstep=2) {
next if $ychop % $divisor;
if ($x % $divisor == 0) {
### common factor with X ...
return undef;
}
$ymult /= $divisor; # one of $divisor divided out
do {
$ychop /= $divisor; # all of $divisor divided out
} until ($ychop % $divisor);
($limit,$overflow) = _limit($ychop); # new lower $limit, perhaps
}
if ($overflow) {
return undef; # Y too big to find all primes
}
# remaining $ychop is a prime, or $ychop==1
if ($ychop > 1) {
if ($x % $ychop == 0) {
### common factor with X ...
return undef;
}
$ymult /= $ychop;
}
return $x*$x * $y*$ymult;
}
}
#------------------------------------------------------------------------------
# all rationals X,Y >= 1 with no common factor
use Math::PlanePath::DiagonalRationals;
*xy_is_visited = Math::PlanePath::DiagonalRationals->can('xy_is_visited');
#------------------------------------------------------------------------------
# even/odd
# X=2^10 -> N=2^20 is X^2
# Y=3 -> N=3
# Y=3^2 -> N=3^3
# Y=3^3 -> N=3^5
# Y=3^4 -> N=3^7
# Y*Y / distinct prime factors
#
# negabinary
# X=prime^2 -> N=prime^6 is X^3
# X=prime^6 -> N=prime^26 is X^4.33
# maximum 101010...10110 -> 1101010...10 approaches factor 5
# same for negatives
#
# revbinary
# X=prime^k -> N=prime^(3k) ix X^3
# not exact
sub rect_to_n_range {
my ($self, $x1,$y1, $x2,$y2) = @_;
### rect_to_n_range()
$x1 = round_nearest ($x1);
$y1 = round_nearest ($y1);
$x2 = round_nearest ($x2);
$y2 = round_nearest ($y2);
my $n = max($x1,$x2) * max($y1,$y2);
my $n_squared = $n * $n;
return (1,
($self->{'factor_coding'} eq 'negabinary'
? ($n_squared*$n_squared) * $n # X^5*Y^5
: $self->{'factor_coding'} eq 'revbinary'
? $n_squared * $n # X^3*Y^3
# even/odd, odd/even
: $n_squared)); # X^2*Y^2
}
#------------------------------------------------------------------------------
# _limit() returns ($limit,$overflow).
#
# $limit is the biggest divisor to attempt trial division of $n. If $n <
# 2^32 then $limit=sqrt($n) and that will find all primes. If $n >= 2^32
# then $limit is smaller than sqrt($n), being calculated from the length of
# $n so as to make a roughly constant amount of time doing divisions. But
# $limit is always at least 50 so as to divide by primes up to 50.
#
# $overflow is a boolean, true if $n is too big to search for all primes and
# $limit is something smaller than sqrt($n). $overflow is false if $limit
# has not been capped and is enough to find all primes.
#
sub _limit {
my ($n) = @_;
my $limit = int(sqrt($n));
my $cap = max (int(65536 * 10 / length($n)),
50);
if ($limit > $cap) {
return ($cap, 1);
} else {
return ($limit, 0);
}
}
1;
__END__
=for stopwords eg Ryde OEIS ie Math-PlanePath Calkin-Wilf McCrimmon Freilich Yoram Sagher negabinary Denumerability
=head1 NAME
Math::PlanePath::FactorRationals -- rationals by prime powers
=head1 SYNOPSIS
use Math::PlanePath::FactorRationals;
my $path = Math::PlanePath::FactorRationals->new;
my ($x, $y) = $path->n_to_xy (123);
=head1 DESCRIPTION
XXXThis path enumerates
rationals X/Y with no common factor, based on the prime powers in numerator
and denominator, as per
=over
Kevin McCrimmon, "Enumeration of the Positive Rationals", American
Math. Monthly, Nov 1960, page 868.
L
Gerald Freilich, "A Denumerability Formula for the Rationals", American
Math. Monthly, Nov 1965, pages 1013-1014.
L
Yoram Sagher, "Counting the rationals", American Math. Monthly, Nov 1989,
page 823. L
=back
The result is
=cut
# math-image --path=FactorRationals,factor_coding=even/odd --all --output=numbers --size=58x16
=pod
15 | 15 60 240 735 960 1815
14 | 14 126 350 1134 1694
13 | 13 52 117 208 325 468 637 832 1053 1300 1573
12 | 24 600 1176 2904
11 | 11 44 99 176 275 396 539 704 891 1100
10 | 10 90 490 810 1210
9 | 27 108 432 675 1323 1728 2700 3267
8 | 32 288 800 1568 2592 3872
7 | 7 28 63 112 175 252 448 567 700 847
6 | 6 150 294 726
5 | 5 20 45 80 180 245 320 405 605
4 | 8 72 200 392 648 968
3 | 3 12 48 75 147 192 300 363
2 | 2 18 50 98 162 242
1 | 1 4 9 16 25 36 49 64 81 100 121
Y=0 |
----------------------------------------------------------
X=0 1 2 3 4 5 6 7 8 9 10 11
A given fraction X/Y with no common factor has a prime factorization
X/Y = p1^e1 * p2^e2 * ...
The exponents e[i] are positive, negative or zero, being positive when the
prime is in the numerator or negative when in the denominator. Those
exponents are represented in an integer N by mapping the exponents to
non-negative,
N = p1^f(e1) * p2^f(e2) * ...
f(e) = 2*e if e >= 0
= 1-2*e if e < 0
f(e) e
--- ---
0 0
1 -1
2 1
3 -2
4 2
For example
X/Y = 125/7 = 5^3 * 7^(-1)
encoded as N = 5^(2*3) * 7^(1-2*(-1)) = 5^6 * 7^1 = 5359375
N=3 -> 3^-1 = 1/3
N=9 -> 3^1 = 3/1
N=27 -> 3^-2 = 1/9
N=81 -> 3^2 = 9/1
The effect is to distinguish prime factors of the numerator or denominator
by odd or even exponents of those primes in N. Since X and Y have no common
factor a given prime appears in one and not the other. The oddness or
evenness of the p^f() exponent in N can then encode which of the two X or Y
it came from.
The exponent f(e) in N has term 2*e in both cases, but the exponents from Y
are reduced by 1. This can be expressed in the following form. Going from
X,Y to N doesn't need to factorize X, only Y.
X^2 * Y^2
N = --------------------
distinct primes in Y
N=1,2,3,8,5,6,etc in the column X=1 is integers with odd powers of prime
factors. These are the fractions 1/Y so the exponents of the primes are all
negative and thus all exponents in N are odd.
XN=1,4,9,16,etc in row Y=1 are the perfect squares. That
row is the integers X/1 so the exponents are all positive and thus in N
become 2*e, giving simply N=X^2.
=head2 Odd/Even
Option C "odd/even"> changes the f() mapping to
numerator exponents as odd numbers and denominator exponents as even.
f(e) = 2*e-1 if e > 0
= -2*e if e <= 0
The effect is simply to transpose XE-EY.
"odd/even" is the form given by Kevin McCrimmon and Gerald Freilich. The
default "even/odd" is the form given by Yoram Sagher.
=head2 Negabinary
XOption C "negabinary"> changes the
f() mapping to negabinary as suggested in
=over
David M. Bradley, "Counting the Positive Rationals: A Brief Survey",
L
=back
=cut
# math-image --path=FactorRationals,factor_coding=negabinary --all --output=numbers_xy --size=70x14
=pod
This coding is not as compact as odd/even and tends to make bigger N values,
13 | 2197 4394 6591 140608 10985 13182 15379 281216
12 | 108 540 756
11 | 1331 2662 3993 85184 6655 7986 9317 170368
10 | 1000 3000 7000
9 | 9 18 576 45 63 1152
8 | 8192 24576 40960 57344
7 | 343 686 1029 21952 1715 2058 43904
6 | 216 1080 1512
5 | 125 250 375 8000 750 875 16000
4 | 4 12 20 28
3 | 27 54 1728 135 189 3456
2 | 8 24 40 56
1 | 1 2 3 64 5 6 7 128
Y=0 |
----------------------------------------------------------
X=0 1 2 3 4 5 6 7 8
=head2 Reversing Binary
Option C "revbinary"> changes the f() mapping to
"reversing binary" where a given integer is represented as a sum of powers
2^k with alternating signs
e = 2^k1 - 2^k2 + 2^k3 - ... 0 <= k1 < k2 < k3
f(e) e
--- ---
0 0
1 1
2 2
3 -1
4 4
5 -3
6 -2
7 3
This representation is per Knuth volume 2 section 4.1 exercise 27. The
exercise there is to show all integers can be represented this way.
=cut
# math-image --path=FactorRationals,factor_coding=revbinary --all --output=numbers --size=15x10
=pod
9 | 729 1458 2916 3645 5103 93312 7290
8 | 32 96 160 224 288
7 | 343 686 1029 1372 1715 2058 43904 3087 3430
6 | 216 1080 1512
5 | 125 250 375 500 750 875 16000 1125
4 | 64 192 320 448 576
3 | 27 54 108 135 189 3456 270
2 | 8 24 40 56 72
1 | 1 2 3 4 5 6 7 128 9 10
Y=0 |
---------------------------------------------------------------
X=0 1 2 3 4 5 6 7 8 9 10
The X axis begins with the integers 1 to 7 because f(1)=1 and f(2)=2 so N=X
until X has a prime p^3 or higher power. The first such is X=8=2^3 which is
f(7)=3 so N=2^7=128.
=head1 FUNCTIONS
See L for behaviour common to all path classes.
=over
=item C<$path = Math::PlanePath::FactorRationals-Enew ()>
=item C<$path = Math::PlanePath::FactorRationals-E