github.com/LanderTome/numerologyCalculator@v1.0.2/README.md (about)

     1  [![Build Status](https://www.travis-ci.com/LanderTome/numerologyCalculator.svg?branch=master)](https://www.travis-ci.com/LanderTome/numerologyCalculator) 
     2  [![Go Report Card](https://goreportcard.com/badge/github.com/LanderTome/numerologyCalculator)](https://goreportcard.com/report/github.com/LanderTome/numerologyCalculator)
     3  [![codecov](https://codecov.io/gh/LanderTome/numerologyCalculator/branch/master/graph/badge.svg?token=UH32UC6AQ0)](https://codecov.io/gh/LanderTome/numerologyCalculator)
     4  [![Go Reference](https://pkg.go.dev/badge/github.com/LanderTome/numerologyCalculator.svg)](https://pkg.go.dev/github.com/LanderTome/numerologyCalculator)
     5  
     6  Proof of concept: [https://numerology.mysticalriver.com](https://numerology.mysticalriver.com)
     7  
     8  ## About the Project
     9  
    10  Using either Pythagorean or Chaldean number systems, this calculator does various common numerological name and date
    11  calculations:
    12  
    13  - Destiny / Expression
    14  - Soul's Urge / Heart's Desire
    15  - Personality
    16  - Hidden Passions
    17  - Karmic Lessons
    18  - Life Path
    19  
    20  The truly unique aspect of this package, however, is that it also provides methods to search for either names or dates
    21  that satisfy various numerological criteria. This is useful if one is trying to find a name for a baby, or a wedding
    22  date that has the desirable numerological properties.
    23  
    24  The way that it does this is using a precomputed table of names with corresponding numerological properties. This allows
    25  the table to be searched for specific names that satisfy given constraints. This method is surprisingly efficient. A
    26  database of 100,000 names with all the necessary pre-calculations is only 13.5 MB and searches take only hundredths of a
    27  second.
    28  
    29  This calculator does not provide any numerological interpretations as part of the package. Just the raw numbers.
    30  
    31  See additional documentation at [pkg.go.dev.](https://pkg.go.dev/github.com/LanderTome/numerologyCalculator)
    32  
    33  ## Getting Started
    34  
    35  `go get "github.com/LanderTome/numerologyCalculator"`
    36  
    37  ### Important numerological concepts
    38  
    39  When doing a name calculation there are three properties that need to be specified that affect the calculation output:
    40  
    41  1. Number System
    42  2. Master Numbers
    43  3. Reduce Words
    44  
    45  The `Number System` is either one of the two most common systems that are used to assign numbers to the letters of
    46  alphabet; Pythagorean and Chaldean.
    47  
    48  The `Master Numbers` are numbers that are considered to have special numerological importance, and are treated in
    49  differently in calculations. The most commonly cited master numbers 11, 22, and 33. However, some consider ALL repeated
    50  numbers to be special, ex. 44, 55, 66, etc. The master numbers that one wants to use can be customized.
    51  
    52  When `Reduce Words` is true, the calculation process sums and reduces each name individually before summing and reducing
    53  those results. When it is false, all the parts of a name are summed and reduced together. The most common way is to sum
    54  and reduce each name individually.
    55  
    56  ### Name calculations
    57  
    58  Start a name calculation with the `Name` function.
    59  
    60  ```go
    61  package main
    62  
    63  import "github.com/LanderTome/numerologyCalculator/numerology"
    64  
    65  func main() {
    66  	numberSystem := numerology.Pythagorean
    67  	masterNumbers := []int{11, 22, 33}
    68  	reduceWords := true
    69  	name := numerology.Name("John Doe", numberSystem, masterNumbers, reduceWords)
    70  }
    71  ```
    72  
    73  The returned struct is now the basis for calculating the numerological properties of the given name.
    74  
    75  Now the various numerological numbers can be calculated by calling the various methods.
    76  
    77  ```go
    78  result := name.Full()
    79  destiny := name.Destiny() // alias for name.Full()
    80  expression := name.Expression() // alias for name.Full()
    81  
    82  result := name.Vowels()
    83  soulsUrge := name.SoulsUrge() // alias for name.Vowels()
    84  heartsDesire := name.HeartsDesire() // alias for name.Vowels()
    85  
    86  result := name.Consonants()
    87  personality := name.Personality() // alias for name.Consonants()
    88  
    89  hiddenPassions := name.HiddenPassions()
    90  karmicLessons := name.KarmicLessons()
    91  ```
    92  
    93  `Full, Vowels, and Consonants` are used instead of the common numerological terms because there are sometimes multiple
    94  acceptable terms, and it can make is easier to understand which calculation is being done because you know what letters
    95  of the name are being used.
    96  
    97  Aliases for the above methods are provided for convenience.
    98  
    99  The returned `NumerologicalResult` struct contains information about the calculation. `Value` is the final reduced
   100  numerological number.
   101  `ReduceSteps` is a slice of numbers that are the numerological values at each stage of the final reducing. `Breakdown`
   102  contains the calculated values for each letter and each name that are used as the basis of the calculations.
   103  
   104  `NumerologicalResult` has a method `Debug()` that returns a multiline string that contains a simplistic breakdown of the
   105  calculation steps. It can be used to visualize the conversion.
   106  
   107  ```go
   108  package main
   109  
   110  import "github.com/LanderTome/numerologyCalculator/numerology"
   111  
   112  func main() {
   113  	numberSystem := numerology.Pythagorean
   114  	masterNumbers := []int{11, 22, 33}
   115  	reduceWords := true
   116  	name := numerology.Name("Janet Audrey Doe", numberSystem, masterNumbers, reduceWords)
   117  	personality := name.Consonants()
   118  	println(personality.Debug())
   119  }
   120  
   121  Output:
   122  J a n e t
   123  1 · 5 · 2 = 8
   124  A u d r e y
   125  · · 4 9 · 7 = 20 = 2
   126  D o e
   127  4 · · = 4
   128  Reduce: 14 = 5
   129  ```
   130  
   131  ### Searching names
   132  
   133  Where this calculator stands apart from other ones is in its ability to search for names that match given numerological
   134  criteria. The idea is to scan a database of names, and find ones that, when combined with given names, have the
   135  numerological properties that are specified. This task can be done with brute force methods, but several tricks as
   136  utilized here to filter out names that we know won't work before actually querying the database.
   137  
   138  ```go
   139  package main
   140  
   141  import "github.com/LanderTome/numerologyCalculator/numerology"
   142  
   143  func main() {
   144  	numberSystem := numerology.Pythagorean
   145  	masterNumbers := []int{11, 22, 33}
   146  	reduceWords := true
   147  	name := numerology.Name("Jane ? Doe", numberSystem, masterNumbers, reduceWords)
   148  	searchOpts := numerology.NameSearchOpts{
   149  		Count:          10,
   150  		Offset:         0,
   151  		Seed:           0,
   152  		Database:       "sqlite://test_names.db",
   153  		Dictionary:     "usa_census",
   154  		Gender:         numerology.Female,
   155  		Sort:           numerology.CommonSort,
   156  		Full:           []int{1, 8, -13},
   157  		Vowels:         []int{4, 5, 6},
   158  		Consonants:     []int{5},
   159  		HiddenPassions: nil,
   160  		KarmicLessons:  nil,
   161  	}
   162  	results, offset, err := name.Search(searchOpts)
   163  }
   164  ```
   165  
   166  `NameSearchOpts` contains the necessary information to do the search. `Count` is the number of results to return in each
   167  batch.
   168  `Offset` is used to return the next batch of results. `Seed` is used for generating the "random" sort results. The seed
   169  needs to be known if batching through random results in order to keep the results consistent. `Dictionary` is the name
   170  of the table in the database that will be searched. *The included test files are from the US Census.* `Gender` allows
   171  the names to be filtered by gender, so the results will be more male or female sounding. `Database`
   172  is the database connection string that connects to the database that has the table to be searched.
   173  
   174  Numerological properties: `Full`, `Vowels`, `Consonants`,
   175  `HiddenPassions`, and `KarmicLessons`. These are all slices of integers that specify what criteria we want. Positive
   176  numbers are numbers that are acceptable. Negative numbers are numbers that are to be excluded. A common use for negative
   177  numbers would be to exclude, what are referred to as, Karmic Debt numbers
   178  (13, 14, 16, 17). By specifying `[]int{-13, -14, -16, -19}`, the search results will not include names with those
   179  numbers.
   180  
   181  The return consists of a slice of `NameNumerology` results, an offset number that indicates where the next batch of
   182  results should begin, and any errors messages that occur. To get the next batch use the given offset number in
   183  the `NameSearchOpts`.
   184  
   185  ### Date calculations
   186  
   187  Date calculation are done with the `Date` function.
   188  
   189  ```go
   190  package main
   191  
   192  import "github.com/LanderTome/numerologyCalculator/numerology"
   193  
   194  func main() {
   195  	dt := numerology.NewDate(2021, 1, 1)
   196  	masterNumbers := []int{11, 22, 33}
   197  	date := numerology.Date(dt, masterNumbers)
   198  }
   199  ```
   200  
   201  The available methods for date numerology are `Event()` and
   202  `LifePath()`.
   203  
   204  ```go
   205  event := name.Event()
   206  lifePath := name.LifePath()
   207  ```
   208  
   209  The only real difference between an event calculation and a life path calculation is that life path takes master numbers
   210  into account. The returned `NumerologicalResult` similar to that which is returned by the `Name` methods.
   211  
   212  ### Searching dates
   213  
   214  The calculator is able to search for dates with specific numerological criteria. Unlike the name search, there are no
   215  clever optimizations to this process. It simply loops through each date, and checks that it meets the criteria. Usually,
   216  the search space for dates is only a few hundred days, so this does not significantly impact performance.
   217  
   218  Life Path numbers have to do with one's date of birth so searching does not make a lot of sense because it is quite
   219  difficult to control when someone is born. Searching dates is better suited for finding ideal wedding or event dates.
   220  
   221  ```go
   222  package main
   223  
   224  import "github.com/LanderTome/numerologyCalculator/numerology"
   225  
   226  func main() {
   227  	dt := numerology.NewDate(2021, 1, 1)
   228  	masterNumbers := []int{11, 22, 33}
   229  	date := numerology.Date(dt, masterNumbers)
   230  
   231  	searchOpts := numerology.DateSearchOpts{
   232  		Count:         10,
   233  		Offset:        0,
   234  		Match:         []int{3, 6},
   235  		MonthsForward: 12,
   236  		Dow:           []int{numerology.Friday, numerology.Saturday},
   237  		LifePath:      false,
   238  	}
   239  	results, offset := date.Search(searchOpts)
   240  }
   241  ```
   242  
   243  `DateSearchOpts` contains the necessary information to do the search. `Count` is the number of results to return in each
   244  batch.
   245  `Offset` is used to return the next batch of results. `Match`
   246  contains the numerological numbers to find. Positive numbers indicate numbers that are acceptable, and Negative numbers
   247  indicate numbers that will be avoided. `MonthsForward` is the number of months to search. It does not necessarily make
   248  sense to search 5 years out for a wedding that you want to have in 1 or 2 years.
   249  `Dow` are days of the week that you want results on. This helps if you are only interested in events that occur on
   250  particular days; like weekends. `LifePath` indicates whether the dates should take Master Numbers into account.
   251  
   252  ## Creating the Database
   253  
   254  Before using the name search functionality, a database needs to be created and populated.
   255  
   256  ```go
   257  package main
   258  
   259  import "github.com/LanderTome/numerologyCalculator/numerology"
   260  
   261  func main() {
   262  	dsn := "sqlite://file::memory:" // Example for testing
   263  	namesDir := "test_names"
   264  	if err := numerology.CreateDatabase(dsn, namesDir); err != nil {
   265  		println(err.Error())
   266  	}
   267  }
   268  ```
   269  
   270  ### Connecting to database
   271  
   272  DSN (data source name) is the connection string for the database to use. This library uses [Gorm](https://gorm.io) for
   273  the database connection. It currently supports MySQL, PostgreSQL, and SQLite, however it is anticipated that SQLite
   274  would be the most common backend used. Go package [xo/dburl](https://github.com/xo/dburl) is used for dsn validation, so
   275  it is useful to look at the documentation there to see acceptable connection string formats.
   276  
   277  *The database connection is exposed in a package var `numerology.DB`. It could theoretically be used to manually attach
   278  a custom Gorm backend, although this feature is untested.*
   279  
   280  ### Source files
   281  
   282  #### CSV structure
   283  
   284  Each csv file needs to have three columns, however **NO HEADERS**.
   285  
   286  The columns are *name*, *gender*, *popularity*.
   287  
   288  ```csv
   289  Mary,F,100
   290  Michael,M,98
   291  John,M,95
   292  Susan,F,94
   293  ```
   294  
   295  The popularity field is used so that names are sorted by how common they are. Often census compilations include
   296  information like this. It is useful to be able to sort by how common a name is because some names that people give their
   297  children are simply bizarre, and it becomes hard to sift through quality names without some control of that.
   298  
   299  *In order to save space in the database, the raw popularity numbers are not stored. They are simply used to order the
   300  names before putting them in the database. Once there, the inserted order of the database is used to establish
   301  popularity.*
   302  
   303  #### Directory layout
   304  
   305  The database is populated by names coming from one or more CSV files based on a particular directory layout.
   306  
   307  ```
   308  baseDir\
   309    ├── table1\
   310    │     ├── file1.csv
   311    │     └── file2.csv
   312    └── table2\
   313          ├── file1.csv
   314          └── file2.csv
   315  ```
   316  
   317  The folder names within the `baseDir` will be used as table names in the database. The names in each csv file in the
   318  table directory will be iterated in ascending order and aggregated before being added to the database.
   319  
   320  *Multiple csv files can be used when inserting into the database. The original source of names was a yearly compilation
   321  of USA Census names. They consisted of the popularity of each name for each year from past to present. The names are
   322  weighted so that current popularity is valued higher than older popularity. As the CSV files are iterated, the
   323  popularity is summed up with a weighted scale based on how many files there are.*
   324  
   325  ## Other notes
   326  
   327  ### Is 'Y' a consonant or a vowel?
   328  
   329  One problem that often comes up when doing name numerology is that sometimes the letter 'Y' is treated as a consonant,
   330  and sometimes it is treated like a vowel. How to handle these situations is, unfortunately, not so straightforward for
   331  an algorithm. The obvious answer is that 'Y' is a consonant when it is used as a consonant in a word, and a vowel when
   332  used as a vowel. But how does one know the difference?
   333  
   334  In the English language, every word can be broken down in to syllables. The rule is that each syllable must have a
   335  vowel. That means that when there is a syllable with no obvious vowels, but there is a 'Y', the 'Y' is treated like a
   336  vowel.
   337  
   338  Take a name like Sydney. The syllables would be `Syd` and `ney`. In
   339  `Syd`, there is no vowel, so the 'Y' functions as a vowel. However, in
   340  `ney`, the 'E' is the vowel, so the 'Y' defaults to a consonant.
   341  
   342  This idea is pretty easy to grasp, but turns out it is hard to program because there is no good algorithm for separating
   343  words (especially names) into syllables. You essentially need a dictionary of the English language (and perhaps others,
   344  as well) because there are different ways to pronounce similarly written words. This is even more difficult for names
   345  because great liberties are often taken with their pronunciation.
   346  
   347  One route is the use machine learning, and train it to deduce the syllable structure of words. This is a lot of work and
   348  overhead for a solution that won't really even be 100% accurate anyway.
   349  
   350  Some numerology calculators allow for special characters to signify when to treat 'Y' differently. Something
   351  like `S*yndey` would use the * symbol to denote that the following 'Y' should be a vowel instead of a consonant. This is
   352  difficult for this library because in order to search it needs to precompute a table of names. In order to do that, the
   353  value of 'Y' needs to be picked ahead of time and in a consistent way. Arbitrarily choosing the value of a 'Y' could
   354  lead to inconsistent name results.
   355  
   356  Luckily, the 'Y' situation does not come up very often, and there are several rules-of-thumb that can be used to pick
   357  the right value most of the time. This is what this library does, however, it does mean that names with 'Y' ought to be
   358  looked at with extra scrutiny.
   359  
   360  ### Transliteration of non-ASCII characters
   361  
   362  The Pythagorean and Chaldean numbers systems are defined for the Latin alphabet A-Z. Of course, some languages have
   363  characters that do not fit into this alphabet. The general consensus is to transliterate those characters to Latin
   364  equivalent characters. This is easy for some characters such as ä, é, or ñ. However, some others are not so easy or
   365  obvious; ex. 张.
   366  
   367  Most calculators just ignore these characters, but we can do better. This library includes a Go
   368  package [mozillazg/go-unidecode](https://github.com/mozillazg/go-unidecode)
   369  that is inspired by a Python port of a well-known Perl package `Text::Unidecode`. The author of the Perl package has
   370  some excellent [information](https://interglacial.com/~sburke/tpj/as_html/tpj22.html)
   371  on the difficulties of transliterating languages. It is worth the read in order to understand the limitations of the
   372  automatic conversion.
   373  
   374  When in doubt, manual transliteration to ASCII characters is recommended.
   375  
   376  ### Unknown Characters
   377  
   378  Even with transliteration of alphabetic characters, it is inevitable that names pop up that have symbols or emojis or
   379  other weird characters. What should a calculator do in this situation? Symbols do not have numerological value, so it
   380  seems like there are two solutions: 1) Error on unknown characters or 2) Give them a zero value.
   381  
   382  Returning an error does not seem quite appropriate because sometimes you want to use strange characters in a name, and
   383  purposefully ignore them. Commonly occurring characters of this sort are spaces, dashes, apostrophes, and periods. It is 
   384  not unusual to have a hyphenated name or to include an apostrophe in a name like in A'isha.
   385  
   386  If someone had a name like 'Crazy! Smith', we could force them to drop the exclamation point to do the calculation, or
   387  we could allow it and just give it no value. That way it calculates with no extra work, and the symbols are reflected as
   388  part of the name.
   389  
   390  The problem with just zeroing out characters is that if someone does not know that a character is being interpreted as
   391  an unknown character then they won't be able to know if the numerological calculation is what they expect. Perhaps
   392  someone expects that
   393  `$amuel $mith` is similar enough to `Samuel Smith` that it is automatically converted.
   394  
   395  The compromise used here is that unknown characters are processed just fine, albeit with a zero value, and all unknown
   396  characters are stored with the name and can be checked with the `UnknownCharacters()`
   397  method.