<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PyPy (Posts by Vilhjálmur Þorsteinsson)</title><link>https://www.pypy.org/</link><description></description><atom:link href="https://www.pypy.org/authors/vilhjalmur-thorsteinsson.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:pypy-dev@pypy.org"&gt;The PyPy Team&lt;/a&gt; </copyright><lastBuildDate>Fri, 10 Jul 2026 07:03:22 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Natural Language Processing for Icelandic with PyPy: A Case Study</title><link>https://www.pypy.org/posts/2022/02/nlp-icelandic-case-study.html</link><dc:creator>Vilhjálmur Þorsteinsson</dc:creator><description>&lt;section id="natural-language-processing-for-icelandic-with-pypy-a-case-study"&gt;
&lt;h2&gt;Natural Language Processing for Icelandic with PyPy: A Case Study&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Icelandic_language"&gt;Icelandic&lt;/a&gt; is one
of the smallest languages of the world, with about 370.000 speakers. It
is a language in the Germanic family, most similar to Norwegian, Danish
and Swedish, but closer to the original &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Old_Norse"&gt;Old
Norse&lt;/a&gt; spoken throughout
Scandinavia until about the 14th century CE.&lt;/p&gt;
&lt;p&gt;As with other small languages, there are &lt;a class="reference external" href="https://www.theguardian.com/world/2018/feb/26/icelandic-language-battles-threat-of-digital-extinction"&gt;worries that the language may
not
survive&lt;/a&gt;
in a digital world, where all kinds of fancy applications are developed
first - and perhaps only - for the major languages. Voice assistants,
chatbots, spelling and grammar checking utilities, machine translation,
etc., are increasingly becoming staples of our personal and professional
lives, but if they don’t exist for Icelandic, Icelanders will gravitate
towards English or other languages where such tools are readily
available.&lt;/p&gt;
&lt;p&gt;Iceland is a technology-savvy country, with &lt;a class="reference external" href="https://ourworldindata.org/grapher/share-of-individuals-using-the-internet?tab=table"&gt;world-leading adoption
rates of the
Internet&lt;/a&gt;,
PCs and smart devices, and a thriving software industry. So the
government figured that it would be worthwhile to fund a &lt;a class="reference external" href="https://aclanthology.org/2020.lrec-1.418.pdf"&gt;5-year
plan&lt;/a&gt; to build natural
language processing (NLP) resources and other infrastructure for the
Icelandic language. The project focuses on collecting data and
developing open source software for a range of core applications, such
as tokenization, vocabulary lookup, n-gram statistics, part-of-speech
tagging, named entity recognition, spelling and grammar checking, neural
language models and speech processing.&lt;/p&gt;
&lt;hr class="docutils"&gt;
&lt;p&gt;My name is Vilhjálmur Þorsteinsson, and I’m the founder and CEO of a
software startup &lt;a class="reference external" href="https://mideind.is/english.html"&gt;Miðeind&lt;/a&gt; in Reykjavík,
Iceland, that employs 10 software engineers and linguists and focuses on
NLP and AI for the Icelandic language. The company participates in the
government’s language technology program, and has contributed
significantly to the program’s core tools (e.g., a tokenizer and a
parser), spelling and grammar checking modules, and a neural machine
translation stack.&lt;/p&gt;
&lt;p&gt;When it came to a choice of programming languages and development tools
for the government program, the requirements were for a major, well
supported, vendor-and-OS-agnostic FOSS platform with a large and diverse
community, including in the NLP space. The decision to select Python as
a foundational language for the project was a relatively easy one. That
said, there was a bit of trepidation around the well known fact that
CPython can be slow for inner-core tasks, such as tokenization and
parsing, that can see heavy workloads in production.&lt;/p&gt;
&lt;p&gt;I first became aware of PyPy in early 2016 when I was developing a
crossword game &lt;a class="reference external" href="https://github.com/mideind/Netskrafl"&gt;Netskrafl&lt;/a&gt; in Python 2.7
for Google App Engine. I had a utility program that compressed a
dictionary into a Directed Acyclic Word Graph and was taking 160
seconds  to run on CPython 2.7, so I tried PyPy and to my amazement saw
a 4x speedup (down to 38 seconds), with literally no effort besides
downloading the PyPy runtime.&lt;/p&gt;
&lt;p&gt;This led me to select PyPy as the default Python interpreter for my
company’s Python development efforts as well as for our production
websites and API servers, a role in which it remains to this day. We
have followed PyPy’s upgrades along the way, being just about to migrate
our minimally required language version from 3.6 to 3.7.&lt;/p&gt;
&lt;p&gt;In NLP, speed and memory requirements can be quite important for
software usability. On the other hand, NLP logic and algorithms are
often complex and challenging to program, so programmer productivity and
code clarity are also critical success factors. A pragmatic approach
balances these factors, avoids premature optimization and seeks a
careful compromise between maximal run-time efficiency and minimal
programming and maintenance effort.&lt;/p&gt;
&lt;p&gt;Turning to our use cases, our Icelandic text
tokenizer &lt;a class="reference external" href="https://github.com/mideind/Tokenizer"&gt;"Tokenizer"&lt;/a&gt; is fairly light,
runs tight loops and performs a large number of small, repetitive
operations. It runs very well on PyPy’s JIT and has not required further
optimization.&lt;/p&gt;
&lt;p&gt;Our Icelandic parser &lt;a class="reference external" href="https://github.com/mideind/GreynirPackage"&gt;Greynir&lt;/a&gt;
(known on PyPI as &lt;a class="reference external" href="https://pypi.org/project/reynir/"&gt;reynir&lt;/a&gt;) is,
if I may say so myself, a piece of work. It &lt;a class="reference external" href="https://aclanthology.org/R19-1160.pdf"&gt;parses natural language
text&lt;/a&gt; according to a
&lt;a class="reference external" href="https://github.com/mideind/GreynirPackage/blob/master/src/reynir/Greynir.grammar"&gt;hand-written context-free
grammar&lt;/a&gt;,
using an &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Earley_parser"&gt;Earley-type
algorithm&lt;/a&gt; as &lt;a class="reference external" href="https://www.sciencedirect.com/science/article/pii/S0167642309000951"&gt;enhanced
by Scott and
Johnstone&lt;/a&gt;.
The CFG contains almost 7,000 nonterminals and 6,000 terminals, and the
parser handles ambiguity as well as left, right and middle recursion. It
returns a packed parse forest for each input sentence, which is then
pruned by a scoring heuristic down to a single best result tree.&lt;/p&gt;
&lt;p&gt;This parser was originally coded in pure Python and turned out to be
unusably slow when run on CPython - but usable on PyPy, where it was
3-4x faster. However, when we started applying it to heavier production
workloads, it  became apparent that it needed to be faster still. We
then proceeded to convert the innermost Earley parsing loop from Python
to &lt;a class="reference external" href="https://github.com/mideind/GreynirPackage/blob/master/src/reynir/eparser.cpp"&gt;tight
C++&lt;/a&gt;
and to call it from PyPy via
&lt;a class="reference external" href="https://cffi.readthedocs.io/en/latest/"&gt;CFFI&lt;/a&gt;, with callbacks for
token-terminal matching functions (“business logic”) that remained on
the Python side. This made the parser much faster (on the order of 100x
faster than the original on CPython) and quick enough for our production
use cases. Even after moving much of the heavy processing to C++ and using CFFI, PyPy still gives a significant speed boost over CPython.&lt;/p&gt;
&lt;p&gt;Connecting C++ code with PyPy proved to be quite painless using CFFI,
although we had to figure out a few &lt;a class="reference external" href="https://github.com/mideind/GreynirPackage/blob/master/src/reynir/eparser_build.py"&gt;magic incantations in our build
module&lt;/a&gt;
to make it compile smoothly during setup from source on Windows and
MacOS in addition to Linux. Of course, we build binary PyPy and CPython
wheels for the most common targets so most users don’t have to worry
about setup requirements.&lt;/p&gt;
&lt;p&gt;With the positive experience from the parser project, we proceeded to
take a similar approach for two other core NLP packages: our compressed
vocabulary package &lt;a class="reference external" href="https://github.com/mideind/BinPackage"&gt;BinPackage&lt;/a&gt;
(known on PyPI as &lt;a class="reference external" href="https://pypi.org/project/islenska/"&gt;islenska&lt;/a&gt;) and our
trigrams database package &lt;a class="reference external" href="https://github.com/mideind/Icegrams"&gt;Icegrams&lt;/a&gt;.
These packages both take large text input (3.1 million word forms with
inflection data in the vocabulary case; 100 million tokens in the
trigrams case) and compress it into packed binary structures. These
structures are then memory-mapped at run-time using
&lt;a class="reference external" href="https://docs.python.org/3/library/mmap.html"&gt;mmap&lt;/a&gt; and queried via
Python functions with a lookup time in the microseconds range. The
low-level data structure navigation is &lt;a class="reference external" href="https://github.com/mideind/Icegrams/blob/master/src/icegrams/trie.cpp"&gt;done in
C++&lt;/a&gt;,
called from Python via CFFI. The ex-ante preparation, packing,
bit-fiddling and data structure generation is fast enough with PyPy, so
we haven’t seen a need to optimize that part further.&lt;/p&gt;
&lt;p&gt;To showcase our tools, we host public (and open source) websites such as
&lt;a class="reference external" href="https://greynir.is/"&gt;greynir.is&lt;/a&gt; for our parsing, named entity
recognition and query stack and
&lt;a class="reference external" href="https://yfirlestur.is/"&gt;yfirlestur.is&lt;/a&gt; for our spell and grammar
checking stack. The server code on these sites is all Python running on
PyPy using &lt;a class="reference external" href="https://flask.palletsprojects.com/en/2.0.x/"&gt;Flask&lt;/a&gt;,
wrapped in &lt;a class="reference external" href="https://gunicorn.org/"&gt;gunicorn&lt;/a&gt; and hosted on
&lt;a class="reference external" href="https://www.nginx.com/"&gt;nginx&lt;/a&gt;. The underlying database is
&lt;a class="reference external" href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; accessed via
&lt;a class="reference external" href="https://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; and
&lt;a class="reference external" href="https://pypi.org/project/psycopg2cffi/"&gt;psycopg2cffi&lt;/a&gt;. This setup
has served us well for 6 years and counting, being fast, reliable and
having helpful and supporting communities.&lt;/p&gt;
&lt;p&gt;As can be inferred from the above, we are avid fans of PyPy and
commensurately thankful for the great work by the PyPy team over the
years. PyPy has enabled us to use Python for a larger part of our
toolset than CPython alone would have supported, and its smooth
integration with C/C++ through CFFI has helped us attain a better
tradeoff between performance and programmer productivity in our
projects. We wish for PyPy a great and bright future and also look
forward to exciting related developments on the horizon, such as
&lt;a class="reference external" href="https://hpyproject.org/"&gt;HPy&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;</description><category>casestudy</category><category>guestpost</category><guid>https://www.pypy.org/posts/2022/02/nlp-icelandic-case-study.html</guid><pubDate>Sun, 06 Feb 2022 15:00:00 GMT</pubDate></item></channel></rss>