First commit

This commit is contained in:
2022-01-13 23:27:39 +01:00
parent dab6549cad
commit f53bf1b804
93 changed files with 11042 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
package obitax
import (
"regexp"
)
func (taxonomy *Taxonomy) IFilterOnName(name string, strict bool) *ITaxonSet {
if strict {
nodes, ok := taxonomy.index[name]
if ok {
return nodes.Iterator()
} else {
empty := make(TaxonSet)
return (&empty).Iterator()
}
}
return taxonomy.Iterator().IFilterOnName(name, strict)
}
func (iterator *ITaxonSet) IFilterOnName(name string, strict bool) *ITaxonSet {
new_iterator := NewITaxonSet()
sentTaxa := make(map[int]bool)
if strict {
go func() {
for iterator.Next() {
taxon := iterator.Get()
if _, ok := sentTaxa[taxon.taxid]; !ok {
if taxon.IsNameEqual(name) {
sentTaxa[taxon.taxid] = true
new_iterator.source <- taxon
}
}
}
close(new_iterator.source)
}()
} else {
pattern := regexp.MustCompile(name)
go func() {
for iterator.Next() {
taxon := iterator.Get()
if _, ok := sentTaxa[taxon.taxid]; !ok {
if taxon.IsNameMatching(pattern) {
sentTaxa[taxon.taxid] = true
new_iterator.source <- taxon
}
}
}
close(new_iterator.source)
}()
}
return new_iterator
}

View File

@@ -0,0 +1,29 @@
package obitax
func (iterator *ITaxonSet) IFilterOnTaxRank(rank string) *ITaxonSet {
new_iter := NewITaxonSet()
go func() {
for iterator.Next() {
taxon := iterator.Get()
if taxon.rank == rank {
new_iter.source <- taxon
}
}
close(new_iter.source)
}()
return new_iter
}
func (set *TaxonSet) IFilterOnTaxRank(rank string) *ITaxonSet {
return set.Iterator().IFilterOnTaxRank(rank)
}
func (slice *TaxonSlice) IFilterOnTaxRank(rank string) *ITaxonSet {
return slice.Iterator().IFilterOnTaxRank(rank)
}
func (taxonomy *Taxonomy) IFilterOnTaxRank(rank string) *ITaxonSet {
return taxonomy.Iterator().IFilterOnTaxRank(rank)
}

View File

@@ -0,0 +1,59 @@
package obitax
import "reflect"
func (iterator *ITaxonSet) IFilterOnSubcladeOf(taxon *TaxNode) *ITaxonSet {
new_iter := NewITaxonSet()
go func() {
for iterator.Next() {
tx := iterator.Get()
if tx.IsSubCladeOf(taxon) {
new_iter.source <- tx
}
}
close(new_iter.source)
}()
return new_iter
}
func (set *TaxonSet) IFilterOnSubcladeOf(taxon *TaxNode) *ITaxonSet {
return set.Iterator().IFilterOnSubcladeOf(taxon)
}
func (slice *TaxonSlice) IFilterOnSubcladeOf(taxon *TaxNode) *ITaxonSet {
return slice.Iterator().IFilterOnSubcladeOf(taxon)
}
func (taxonomy *Taxonomy) IFilterOnSubcladeOf(taxon *TaxNode) *ITaxonSet {
return taxonomy.Iterator().IFilterOnSubcladeOf(taxon)
}
func (iterator *ITaxonSet) IFilterBelongingSubclades(clades *TaxonSet) *ITaxonSet {
if len(*clades) == 0 {
return iterator
}
// Considers the second simplest case when only
// a single subclase is provided
if len(*clades) == 1 {
keys := reflect.ValueOf(*clades).MapKeys()
return iterator.IFilterOnSubcladeOf((*clades)[int(keys[0].Int())])
}
new_iter := NewITaxonSet()
go func() {
for iterator.Next() {
tx := iterator.Get()
if tx.IsBelongingSubclades(clades) {
new_iter.source <- tx
}
}
close(new_iter.source)
}()
return new_iter
}

View File

@@ -0,0 +1,21 @@
package obitax
func (taxon *TaxNode) IsSubCladeOf(parent *TaxNode) bool {
for taxon.taxid != parent.taxid && taxon.parent != taxon.taxid {
taxon = taxon.pparent
}
return taxon.taxid == parent.taxid
}
func (taxon *TaxNode) IsBelongingSubclades(clades *TaxonSet) bool {
_, ok := (*clades)[taxon.taxid]
for !ok && taxon.parent != taxon.taxid {
taxon = taxon.pparent
_, ok = (*clades)[taxon.taxid]
}
return ok
}

99
pkg/obitax/iterator.go Normal file
View File

@@ -0,0 +1,99 @@
package obitax
type ITaxonSet struct {
source chan *TaxNode
current *TaxNode
finished bool
p_finished *bool
}
func NewITaxonSet() *ITaxonSet {
i := ITaxonSet{make(chan *TaxNode), nil, false, nil}
i.p_finished = &i.finished
return &i
}
func (set *TaxonSet) Iterator() *ITaxonSet {
i := NewITaxonSet()
go func() {
for _, t := range *set {
i.source <- t
}
close(i.source)
}()
return i
}
func (set *TaxonSlice) Iterator() *ITaxonSet {
i := NewITaxonSet()
go func() {
for _, t := range *set {
i.source <- t
}
close(i.source)
}()
return i
}
func (taxonmy *Taxonomy) iterator() *ITaxonSet {
return taxonmy.nodes.Iterator()
}
func (iterator *ITaxonSet) Next() bool {
if *(iterator.p_finished) {
return false
}
next, ok := (<-iterator.source)
if ok {
iterator.current = next
return true
}
iterator.current = nil
*iterator.p_finished = true
return false
}
// The 'Get' method returns the instance of *TaxNode
// currently pointed by the iterator. You have to use the
// 'Next' method to move to the next entry before calling
// 'Get' to retreive the following instance.
func (iterator *ITaxonSet) Get() *TaxNode {
return iterator.current
}
// Finished returns 'true' value if no more data is available
// from the iterator.
func (iterator *ITaxonSet) Finished() bool {
return *iterator.p_finished
}
func (iterator *ITaxonSet) Split() *ITaxonSet {
new_iter := ITaxonSet{iterator.source, nil, false, iterator.p_finished}
return &new_iter
}
func (iterator *ITaxonSet) TaxonSet() *TaxonSet {
set := make(TaxonSet)
for iterator.Next() {
taxon := iterator.Get()
set[taxon.taxid] = taxon
}
return &set
}
func (iterator *ITaxonSet) TaxonSlice() *TaxonSlice {
slice := make(TaxonSlice, 0)
for iterator.Next() {
taxon := iterator.Get()
slice = append(slice, taxon)
}
return &slice
}

36
pkg/obitax/path.go Normal file
View File

@@ -0,0 +1,36 @@
package obitax
import (
"errors"
"fmt"
)
func (taxon *TaxNode) Path() (*TaxonSlice, error) {
path := make(TaxonSlice, 0, 30)
path = append(path, taxon)
for taxon != taxon.pparent {
taxon = taxon.pparent
if taxon == nil {
return nil, errors.New(fmt.Sprint("Taxonomy must be reindexed"))
}
path = append(path, taxon)
}
return &path, nil
}
// Returns a TaxonSet listing the requested taxon and all
// its ancestors in the taxonomy down to the root.
func (taxonomy *Taxonomy) Path(taxid int) (*TaxonSlice, error) {
taxon, err := taxonomy.Taxon(taxid)
if err != nil {
return nil, err
}
return taxon.Path()
}

16
pkg/obitax/ranklist.go Normal file
View File

@@ -0,0 +1,16 @@
package obitax
func (taxonomy *Taxonomy) RankList() []string {
ranks := make([]string, 0, 30)
mranks := make(map[string]bool)
for _, t := range *taxonomy.nodes {
mranks[t.rank] = true
}
for r := range mranks {
ranks = append(ranks, r)
}
return ranks
}

66
pkg/obitax/taxon.go Normal file
View File

@@ -0,0 +1,66 @@
package obitax
import (
"regexp"
)
type TaxNode struct {
taxid int
parent int
pparent *TaxNode
rank string
scientificname *string
alternatenames *map[string]*string
}
func NewTaxNode(taxid int, parent int, rank string) *TaxNode {
n := TaxNode{taxid, parent, nil, rank, nil, nil}
return &n
}
func (node *TaxNode) ScientificName() string {
n := node.scientificname
if n == nil {
return ""
}
return *n
}
func (node *TaxNode) Rank() string {
return node.rank
}
func (node *TaxNode) Taxid() int {
return node.taxid
}
func (node *TaxNode) Parent() *TaxNode {
return node.pparent
}
func (node *TaxNode) IsNameEqual(name string) bool {
if *(node.scientificname) == name {
return true
}
if node.alternatenames != nil {
_, ok := (*node.alternatenames)[name]
return ok
}
return false
}
func (node *TaxNode) IsNameMatching(pattern *regexp.Regexp) bool {
if pattern.MatchString(*(node.scientificname)) {
return true
}
if node.alternatenames != nil {
for n := range *node.alternatenames {
if pattern.MatchString(n) {
return true
}
}
}
return false
}

135
pkg/obitax/taxonomy.go Normal file
View File

@@ -0,0 +1,135 @@
package obitax
import (
"errors"
"fmt"
"log"
)
type TaxName struct {
name *string
nameclass *string
}
type Taxonomy struct {
nodes *TaxonSet
alias map[int]*TaxNode
index map[string]*TaxonSet
}
func NewTaxonomy() *Taxonomy {
set := make(TaxonSet)
taxonomy := Taxonomy{
nodes: &set,
alias: make(TaxonSet),
index: make(map[string]*TaxonSet)}
return &taxonomy
}
func (taxonomy *Taxonomy) TaxonSet() *TaxonSet {
return taxonomy.nodes
}
func (taxonomy *Taxonomy) Alias() *map[int]*TaxNode {
return &(taxonomy.alias)
}
func (taxonomy *Taxonomy) Index() *map[string]*TaxonSet {
return &(taxonomy.index)
}
func (taxonomy *Taxonomy) Length() int {
return len(*taxonomy.nodes)
}
func (taxonomy *Taxonomy) Iterator() *ITaxonSet {
return taxonomy.nodes.Iterator()
}
func (taxonomy *Taxonomy) AddNewTaxa(taxid, parent int, rank string, replace bool, init bool) (*TaxNode, error) {
if !replace {
_, ok := (*taxonomy.nodes)[taxid]
if ok {
return nil, errors.New(fmt.Sprintf("Trying to add taxoon %d already present in the taxonomy", taxid))
}
}
n := NewTaxNode(taxid, parent, rank)
(*taxonomy.nodes)[taxid] = n
return n, nil
}
func (taxonomy *Taxonomy) Taxon(taxid int) (*TaxNode, error) {
t, ok := (*taxonomy.nodes)[taxid]
if !ok {
a, aok := taxonomy.alias[taxid]
if !aok {
return nil, errors.New(fmt.Sprintf("Taxid %d is not part of the taxonomy", taxid))
}
log.Printf("Taxid %d is deprecated and must be replaced by %d", taxid, a.taxid)
t = a
}
return t, nil
}
func (taxonomy *Taxonomy) AddNewName(taxid int, name, nameclass *string) error {
node, node_err := taxonomy.Taxon(taxid)
if node_err != nil {
return node_err
}
if *nameclass == "scientific name" {
node.scientificname = name
} else {
names := node.alternatenames
if names == nil {
n := make(map[string]*string)
names = &n
node.alternatenames = names
} else {
(*names)[*name] = nameclass
}
}
i, ok := taxonomy.index[*name]
if !ok {
tnm := make(TaxonSet)
i = &tnm
taxonomy.index[*name] = i
}
(*i)[taxid] = node
return nil
}
func (taxonomy *Taxonomy) ReindexParent() error {
var ok bool
for _, taxon := range *taxonomy.nodes {
taxon.pparent, ok = (*taxonomy.nodes)[taxon.parent]
if !ok {
return errors.New(fmt.Sprintf("Parent %d of taxon %d is not defined in taxonomy",
taxon.taxid,
taxon.parent))
}
}
return nil
}
func MakeTaxName(name, nameclass *string) *TaxName {
tn := TaxName{name, nameclass}
return &tn
}
func (taxonomy *Taxonomy) AddNewAlias(newtaxid, oldtaxid int) error {
n, node_err := taxonomy.Taxon(newtaxid)
if node_err != nil {
return node_err
}
taxonomy.alias[oldtaxid] = n
return nil
}

15
pkg/obitax/taxonset.go Normal file
View File

@@ -0,0 +1,15 @@
package obitax
type TaxonSet map[int]*TaxNode
func (set *TaxonSet) Get(i int) *TaxNode {
return (*set)[i]
}
func (set *TaxonSet) Length() int {
return len(*set)
}
func (set *TaxonSet) Inserts(taxon *TaxNode) {
(*set)[taxon.taxid] = taxon
}

11
pkg/obitax/taxonslice.go Normal file
View File

@@ -0,0 +1,11 @@
package obitax
type TaxonSlice []*TaxNode
func (set *TaxonSlice) Get(i int) *TaxNode {
return (*set)[i]
}
func (set *TaxonSlice) Length() int {
return len(*set)
}