# sanskrit


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Why every store gets this

Before the fold, a Sanskrit query found nothing:

<table>
<thead>
<tr>
<th>query</th>
<th>against</th>
<th>hits</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>देवी</code></td>
<td><code>दे॒वी</code>, the same word accented</td>
<td>0</td>
</tr>
<tr>
<td><code>श्रीमाता</code></td>
<td><code>śrīmātā</code>, the same word in IAST</td>
<td>0</td>
</tr>
<tr>
<td><code>kuṇḍa</code></td>
<td><code>cidagnikuṇḍasambhūtā</code></td>
<td>0</td>
</tr>
</tbody>
</table>

The fix is to fold both scripts to one lossy ASCII key at index time,
rather than transliterate at query time. `simplify casefold` already
turns IAST `śrīmātā` into `srimata`;
[`deva2ascii`](https://Karthik777.github.io/litesearch/sanskrit.html#deva2ascii)
is chosen so Devanagari `श्रीमाता` lands on `srimata` too.

This is on for every store, not only Sanskrit ones, because it costs
nothing on English text and it is the largest measured retrieval win in
the repository. Everything else about Sanskrit, metre, verse chunking,
citations and lemmas, is in
[ganapati](https://github.com/vedicreader/ganapati).

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L76"
target="_blank" style="float:right; font-size:smaller">source</a>

### fold_token

``` python
def fold_token(
    s:str
)->str:
```

*The ASCII index key for one token, whatever script it arrived in.*

Cached because it is called once per token per FTS write *and* per
query, and a corpus is a small vocabulary repeated: 70,413 tokens of the
eval corpus are 4,153 distinct strings, so 94% of the calls are asking a
question that has already been answered. It is three unicode
normalisations and a per-character category scan deep, which is why it
was a third of the cost of indexing a corpus with no Sanskrit in it at
all. Pure function of `s`, so the cache is only ever a memo — same
output, 5.5x fewer of them computed.

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L67"
target="_blank" style="float:right; font-size:smaller">source</a>

### detect_script

``` python
def detect_script(
    s:str
)->str:
```

*`'deva'`, `'latn'` or `'other'` — enough to pick a folding path.*

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L40"
target="_blank" style="float:right; font-size:smaller">source</a>

### deva2ascii

``` python
def deva2ascii(
    s:str
)->str:
```

*Devanagari to a bare ASCII key, applying the implicit `a` of an
unmarked consonant.*

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L35"
target="_blank" style="float:right; font-size:smaller">source</a>

### strip_vedic

``` python
def strip_vedic(
    s:str
)->str:
```

*Drop Vedic tone marks from Devanagari, leaving Latin diacritics alone.
NFC out.*

## The tokenizer

The fold could have been a second indexed column, the way an application
usually does it. As an FTS5 tokenizer instead it needs no schema change,
no second column and no query rewriting, and it works for any store that
already exists.

[`sanskrit_tokenizer`](https://Karthik777.github.io/litesearch/sanskrit.html#sanskrit_tokenizer)
wraps another tokenizer rather than replacing it. It emits the fold as a
colocated token inside porter, so English keeps its stemming and
identifiers stay whole.

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L107"
target="_blank" style="float:right; font-size:smaller">source</a>

### register_sanskrit

``` python
def register_sanskrit(
    db
):
```

*Register the `sanskrit` FTS5 tokenizer on a connection. Idempotent.*

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L91"
target="_blank" style="float:right; font-size:smaller">source</a>

### sanskrit_tokenizer

``` python
def sanskrit_tokenizer(
    con, args
):
```

*A* wrapping\* FTS5 tokenizer that folds Sanskrit so a query matches
regardless of script.\*

## Citations

`CITE_RE` matches a GRETIL citation, `// Mn_1.1 //` or
`|| BrhUp_1,1.2 ||`. It lives here because `tree.py` builds the document
tree out of it: the citation is the verse’s address, so a Sanskrit
source gets a real tree with no markup at all.

------------------------------------------------------------------------

<a
href="https://github.com/Karthik777/litesearch/blob/main/litesearch/sanskrit.py#L116"
target="_blank" style="float:right; font-size:smaller">source</a>

### cite_parts

``` python
def cite_parts(
    c:str
)->tuple:
```

*`'BrhUp_1,1.2'` -\> `('BrhUp', ['1','1','2'])` — the siglum and its
hierarchy.*

``` python
from litesearch.sanskrit import cite_parts

assert cite_parts('BrhUp_1,1.2') == ('BrhUp', ['1','1','2'])
assert cite_parts('Mn_1.1') == ('Mn', ['1','1'])
assert cite_parts('IsUp_4[57M]') == ('IsUp', ['4'])      # the alternate-edition number is dropped
assert cite_parts('not a citation') == ('not a citation', [])
```
