a3nm's bloghttps://a3nm.net/blog/Mon, 18 Jul 2016 22:43:57 +0200Trying btrfs... and giving up for nowhttps://a3nm.net/blog/btrfs_giving_up.html<p>I recently tried to use btrfs to manage some data. My main use case was
<a href="https://btrfs.wiki.kernel.org/index.php/Incremental_Backup">incremental
backups</a> relying on
btrfs's snapshot feature. Indeed, btrfs allows
you to:</p>
<ul>
<li>create <strong>snapshots</strong> of your filesystem at various points in time: the snapshots
essentially take no additional space, except that files of that FS will not
really be deleted as long as they survive in a snapshot;</li>
<li><strong>send</strong> snapshots to remote hosts, even computing efficiently the <strong>diff</strong> between
each snapshot and the previous one, to minimize IO, bandwidth, and backup
storage costs;</li>
<li><strong>browse</strong> old snapshots seamlessly as if they were actual folders, and
restoring files easily.</li>
</ul>
<p>This is much better than my current solution, which is to use rsync. Indeed, by
contrast, rsync has the following drawbacks:</p>
<ul>
<li>rsync only synchronizes the <strong>current version</strong> (overwriting the previous one),
and if you want to keep multiple versions they are not compressed relative
to each other;</li>
<li>each rsync must <strong>rescan the entire filesystem</strong>, even if almost nothing has
changed;</li>
<li>rsync is <strong>not always intelligent about transfers</strong>, as it tries to avoid
re-sending files that haven't changed, but receives no help from the FS to
understand what went on: for instance, if you move a
large directory on the master, in most cases rsync will fail to notice and re-transfer the
whole directory to the backup.</li>
</ul>
<p>This post is a terse documentation of what I have learnt about btrfs in the
process of exploring it.
Sadly, the main outcome of my investigations is that <strong>btrfs does not seem
sufficiently mature for me to use it yet</strong>.
I am sorry about the negative conclusion: I think that
btrfs is a great project and I imagine that the remaining rough edges will
eventually be fixed.
Further, the good news is that (as far as I can tell) I have only encountered
crashes but I have not encountered any data loss issue.</p>
<h2>General considerations about btrfs</h2>
<p>So here are some <strong>general things about btrfs</strong> that I
discovered when playing around:</p>
<ul>
<li>btrfs supports <a href="https://btrfs.wiki.kernel.org/index.php/Compression">transparent file
compression</a> with zlib
and lzo. This is done by passing an option to mount. I am not too sure about
what happens if you forget to pass this option (or pass the wrong value for
this option). It seems to work fine, though.</li>
<li>btrfs supports
<a href="https://btrfs.wiki.kernel.org/index.php/Deduplication">deduplication</a>, but
it turns out that this did not mean what I thought it would.<br/> Unlike, e.g.,
git repositories, if you write data to the disk which happens to already
exist someplace else, btrfs will <em>not</em> notice it and use it to share space.
What it means is that btrfs supports
<em><a href="https://en.wikipedia.org/wiki/Copy-on-write">copy-on-write</a></em>, i.e., when you
write data on the FS that comes from another file of the FS, then btrfs will
only save a pointer to the old data, and will not create two different
copies until one piece of data is modified.
<br/>This implies that, if you want to
deduplicate data which has not been created using copies, you need to do it
offline with specific tools: btrfs does not support it out of the box. I
tried <a href="https://github.com/g2p/bedup">bedup</a>, which was quite slow; its
savings amounted to 110 GB out of 2.6 TB of data when I tested it on a
partition. (Of course, your mileage may vary.) It is quite worrying that the
deduplication tools (in particular,
<a href="https://github.com/g2p/bedup#implementation">bedup</a>) do not seem very sure
of what they are doing, so this does not give at all the impression of being
robust.</li>
<li>btrfs supports many nice features that I didn't need: splitting a FS across
multiple devices (with replication or not), adding/removing devices on the
fly, performing resizes online, etc. I did not try these features out.</li>
</ul>
<p>Here are <strong>things you will need to know</strong> when trying out btrfs, and traps in which you
may fall:</p>
<ul>
<li>The btrfs utilities are not shipped with Debian by default, you need to
<code>apt-get install btrfs-tools</code>.</li>
<li>If you want to start playing with btrfs, you will probably want to convert
data from an ext3 or ext4 partition. There is
a tool designed to do that,
<a href="https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-convert">btrfs-convert</a>,
but <a href="https://btrfs.wiki.kernel.org/index.php/Conversion_from_Ext3">closer
inspection</a>
reveals that it is now reported to be unreliable.<br/>As I
didn't want to build the FS on shaky foundations, I created a partition
from scratch, and moved my terabytes of data around.</li>
<li>When creating test filesystems, note that you cannot create btrfs filesystems
that are too small (apparently, less than 100 MB), and you will get a <a href="https://bugzilla.kernel.org/show_bug.cgi?id=112461">confusing error
message</a> if you try.</li>
<li>btrfs exposes quite a lot of its internals which you apparently may need to be
aware of. In particular, you may have to
<a href="https://btrfs.wiki.kernel.org/index.php/Gotchas#Fragmentation">defragment</a>
it<sup id="fnref:btrfs_giving_up_troll"><a class="footnote-ref" href="#fn:btrfs_giving_up_troll" rel="footnote">1</a></sup>. It seems that you may <a href="http://marc.merlins.org/perso/btrfs/post_2014-05-04_Fixing-Btrfs-Filesystem-Full-Problems.html">also
need</a> to balance the
filesystem (amongst other things) to avoid problems when it is full</li>
<li>btrfs makes it possible to have <em>subvolumes</em> which you can mount
independently. In other words, if your disk contains games and music,
you could imagine having a subvolume <code>games/</code> and a subvolume <code>music/</code>, and
mounting only one of the two (or mounting them at different endpoints). In
this case, if you mount the root of the filesystem, <code>games/</code> and <code>music/</code>
will appear as folders (which are actually different filesystems).<br/>
This means that you should be careful when starting to organize your
filesystem: the root of the filesystem doesn't play the same role as in
other filesystems, and you should probably always be mounting a subvolume of
it instead. If you miss this point initially and want to change your mind
later, it's <a href="https://superuser.com/a/472860/77814">not so simple</a>.</li>
<li>While btrfs supports copy-on-write, <code>cp</code> will not
use it by default. You need to pass the option: <code>--reflink=always</code> to <code>cp</code>, as
explained in <a href="https://btrfs.wiki.kernel.org/index.php/Problem_FAQ#Copy-on-write_doesn.27t_work">this FAQ
entry</a>.
This is a bit unpleasant because it means that scripts must be using <code>cp</code>
properly to take advantage of copy-on-write, and that other programs will
not necessarily support it. In particular, rsync <a href="https://bugzilla.samba.org/show_bug.cgi?id=10170">does
not</a>, for now.</li>
</ul>
<h2>Incremental backups: snapshotting, sending, receiving</h2>
<p>Now, here is more about my specific experience with subvolumes, snapshots, and
<code>btrfs send</code> and <code>btrfs receive</code>, which were the main features I was interested
in. In summary, here are the <strong>basic principles</strong>:</p>
<ul>
<li>You can run <code>btrfs subvolume snapshot foo/ snap/</code> to create a snapshot of <code>foo/</code> as
<code>snap/</code>. This creates <code>snap/</code> as a folder (but it's actually a different
subvolume), which contains the contents of <code>foo/</code> (using copy-on-write, so
without duplicating the actual contents on disk).
For backups, you want to create read-only
snapshots (<code>btrfs subvolume snapshot -r</code>).<br />If you create snapshots at
different points in time, you do not need (and cannot) tell <code>btrfs subvolume snapshot</code> which ones are the most
recent: however, for your own purposes, you should probably indicate it in
the filename.<br/>You can be quite
trigger-happy with snapshots, I created one every hour for weeks
without any problem.</li>
<li>You can run <code>btrfs send snap/</code> to produce on standard output a representation
of the (read-only) snapshot <code>snap/</code>. Alternatively, you can run <code>btrfs send -p old_snap/
snap/</code> to prepare efficiently a compressed representation of <code>snap/</code> that
relies on <code>old_snap/</code>. I tested that, indeed, when the difference from
<code>old_snap/</code> to <code>snap/</code> is that a very large folder was moved, <code>btrfs send</code>
is able to create a very concise representation in comparatively little
time.</li>
<li>You can run <code>btrfs receive snapshots/</code>, where <code>snapshots/</code> is in the backup
FS, to read on standard input a dump produced by <code>btrfs send</code>, and create in <code>snapshots/</code>
the corresponding snapshot (here, <code>snap/</code>: the name depends on what <code>btrfs
send</code> is sending). Of course, the backup FS can be
on a different machine: you can pipe the stream across
<code>ssh</code>, or simply store it to a
file and move that from one machine to the other.</li>
</ul>
<p>That's the theory. Now, details and traps. First, about <strong>snapshot creation</strong>:</p>
<ul>
<li>When creating snapshots periodically, it is quite easy to end up with
filesystems with a very large number of files (which are very similar copies
of the same hierarchy). This is very undesirable, e.g., for
<a href="https://en.wikipedia.org/wiki/Locate_%28Unix%29">locate</a>:
I had <a href="http://linux.die.net/man/8/updatedb">updatedb</a> wasting lots of CPU and disk
space indexing a large number of these snapshots and polluting my <code>locate</code>
results. You'll want to tell
<code>updatedb</code> not to explore the snapshot folder, using the setting <code>PRUNEPATHS</code>
in <code>/etc/updatedb.conf</code>.</li>
<li>In terms of access rights, you do not need to be root to create a
snapshot (or subvolume). Indeed, if you couldn't read some files in the source,
you will still be unable to read them from the snapshot.<br/>
However,
deleting subvolumes is not possible as an unprivileged user unless you pass
a specific <a href="https://unix.stackexchange.com/q/149513/8446">mount option</a>: I
am not sure of the implications of this, in particular, I do not know why it is not the
default. Further,
deleting subvolumes that were created to be read-only requires <a href="https://unix.stackexchange.com/a/150102/8446">a specific
step</a> to make them writable.<br/>Another thing to
understand is that, to remove a subvolume, whether as root or otherwise,
using <code>rm</code> will fail with <code>Operation not permitted</code>; a different error than
the usual <code>Permission denied</code>, but a possible source of confusion. You
should be using <code>btrfs subvolume delete</code> instead.</li>
<li>Having snapshots also makes it quite complicated to
understand where your disk space is going. Is it used by files currently in
your FS? Or files
deleted in the FS but retained because of some snapshot? If so, which snapshot(s)? How many
space would you reclaim by removing a given snapshots, or, say, all snapshots older than one month?<br/>To answer such
questions, you need to use (in particular, enable) btrfs's <a href="https://btrfs.wiki.kernel.org/index.php/Quota_support">quota
support</a>. But even
then it is <a href="http://dustymabe.com/2013/09/22/btrfs-how-big-are-my-snapshots/">not
very
obvious</a> to
figure all of this out.</li>
</ul>
<p>About <strong>sending and receiving snapshots</strong>:</p>
<ul>
<li><code>btrfs send</code> <a href="https://www.spinics.net/lists/linux-btrfs/msg31188.html">requires
root</a>, even for
snapshots that you created: this is unsurprising, as remember that you can
snapshot files that you cannot read, and of course you shouldn't be able to
read them from
the output of <code>btrfs send</code></li>
<li>You <a href="https://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg31535.html">should not interrupt</a>
<code>btrfs send</code> or <code>btrfs receive</code>, either with SIGSTOP or by putting the
computer in hibernation mode. If you do so, the operation will fail. In
particular, an incomplete copy of the subvolume will
<a href="https://github.com/digint/btrbk/issues/17">stay around</a> on the receiving
end, which can easily
mislead you and make you believe that the operation succeeded.
Apparently, btrfs is smart enough to notice that the copy is incomplete (in
particular, fortunately, refusing to use it as a parent to reconstruct
another snapshot), but it is not sufficiently intelligent to delete the leftover
files or (preferably) resuming the operation from where it left, like rsync
does. This means that, in practice, you probably want to snapshot often and have
relatively small diffs between snapshots.<br/>Also note that <code>btrfs send</code> and
<code>btrfs receive</code> give no progress information when they run.</li>
<li>Once you have created snapshots and you want to transfer them to the backup
host, the problem is figuring out which backup depends on which, and what to
send. You can only choose this at the level of <code>btrfs send</code>: snapshot
creation does not need a parent, and <code>btrfs receive</code> is apparently able to
use some ID specified in the <code>btrfs send</code> invocation to identify which
volume it should use (or fail if a suitable volume does not exist, although
I don't know whether this check is bulletproof or not).</li>
<li>Hence, when sending snapshots, btrfs leaves you free to choose the right set
of <code>send</code> operations with the right parents to minimize IO and network
cost.<br/>
A program called
<a href="https://github.com/AmesCornish/buttersink">buttersink</a> attempts to do this,
i.e., choosing an intelligent sequence of transfers. For my use case, sadly, it <a href="https://github.com/AmesCornish/buttersink/issues/26">did not
work</a>. This is
pretty surprising, as my case is quite simple: a series of chronological
snapshots, each of which should be sent based on the previous one. Maybe
the reason is that buttersink does not know in which order the snapshots
were made, and relies on a size estimation of the diff between two btrfs
snapshots, which apparently is both slow to compute and wildly
inaccurate.<br/>
So I wrote instead a <a href="/git/mybin/tree/btrfs_incremental_send">much simpler
script</a> which order the snapshots by
date (as indicated in their name) and sends them in that order. There are
probably exist more elaborate tools for that purpose, like
<a href="https://github.com/digint/btrbk">btrbk</a> which I did not test.</li>
</ul>
<h2>Messy problems</h2>
<p>And finally, here are the <strong>nasty problems</strong> I ran into. When running my script to perform
the transfers, and disconnecting hard drives at random points to simulate
messy hardware failures, I observed the following:</p>
<ul>
<li>Backtraces in syslog suggesting a problem with btrfs (even during normal
operation, I think):</li>
</ul>
<div class="codehilite"><pre><span></span><span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405416</span><span class="p">]</span> <span class="o">------------</span><span class="p">[</span> <span class="n">cut</span> <span class="n">here</span> <span class="p">]</span><span class="o">------------</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405456</span><span class="p">]</span> <span class="nl">WARNING</span><span class="p">:</span> <span class="nl">CPU</span><span class="p">:</span> <span class="mi">0</span> <span class="nl">PID</span><span class="p">:</span> <span class="mi">12046</span> <span class="n">at</span> <span class="o">/</span><span class="n">build</span><span class="o">/</span><span class="n">linux</span><span class="o">-</span><span class="n">HoPide</span><span class="o">/</span><span class="n">linux</span><span class="o">-</span><span class="mf">4.5.1</span><span class="o">/</span><span class="n">fs</span><span class="o">/</span><span class="n">btrfs</span><span class="o">/</span><span class="n">qgroup</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">2650</span> <span class="n">btrfs_qgroup_free_meta</span><span class="o">+</span><span class="mh">0x88</span><span class="o">/</span> <span class="mh">0x90</span> <span class="p">[</span><span class="n">btrfs</span><span class="p">]()</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405459</span><span class="p">]</span> <span class="n">Modules</span> <span class="n">linked</span> <span class="k">in</span><span class="o">:</span> <span class="n">ufs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">qnx4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hfsplus</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hfs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">minix</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ntfs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">vfat</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">msdos</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">fat</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">jfs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xfs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">libcrc32c</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">crc32c_generic</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">vboxpci</span><span class="p">(</span><span class="n">OE</span><span class="p">)</span> <span class="n">vboxnetadp</span><span class="p">(</span><span class="n">OE</span><span class="p">)</span> <span class="n">vboxnetflt</span><span class="p">(</span><span class="n">OE</span><span class="p">)</span> <span class="n">vboxdrv</span><span class="p">(</span><span class="n">OE</span><span class="p">)</span> <span class="n">veth</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ebtable_filter</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ebtables</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xt_conntrack</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ipt_MASQUERADE</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_nat_masquerade_ipv4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xt_addrtype</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">br_netfilter</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">bridge</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">stp</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">llc</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">overlay</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">pci_stub</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nfsd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">auth_rpcgss</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nfs_acl</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">lockd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">grace</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">sunrpc</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">fuse</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ip6t_REJECT</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_reject_ipv6</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ip6table_filter</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ip6_tables</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">iptable_nat</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_conntrack_ipv4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_defrag_ipv4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_nat_ipv4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_nat</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_conntrack</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ipt_REJECT</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">nf_reject_ipv4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xt_tcpudp</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xt_owner</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xt_multiport</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">iptable_filter</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ip_tables</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">x_tables</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">binfmt_misc</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">quota_v2</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">quota_tree</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">dm_crypt</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">algif_skcipher</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">af_alg</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_codec_hdmi</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">uas</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">usb_storage</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">iTCO_wdt</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">iTCO_vendor_support</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ppdev</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">intel_rapl</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">x86_pkg_temp_thermal</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">intel_powerclamp</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">kvm_intel</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">kvm</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">irqbypass</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">crct10dif_pclmul</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">crc32_pclmul</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ghash_clmulni_intel</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hmac</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">dm_mod</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">drbg</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ansi_cprng</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">aesni_intel</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">aes_x86_64</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">lrw</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">gf128mul</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">glue_helper</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ablk_helper</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">cryptd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">uvcvideo</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">pcspkr</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_codec_realtek</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">sg</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">serio_raw</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_codec_generic</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">videobuf2_vmalloc</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">i2c_i801</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">i915</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">videobuf2_memops</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">videobuf2_v4l2</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">videobuf2_core</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">drm_kms_helper</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_usb_audio</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">videodev</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_intel</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">media</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_codec</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_usbmidi_lib</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_rawmidi</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hda_core</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_seq_device</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_hwdep</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_pcm_oss</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">drm</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_mixer_oss</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_pcm</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd_timer</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">evdev</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">joydev</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">lpc_ich</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">snd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">mei_me</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">cdc_acm</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">mfd_core</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">i2c_algo_bit</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">soundcore</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">mei</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">shpchp</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="mi">8250</span><span class="n">_fintek</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">battery</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">parport_pc</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">parport</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">video</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">soc_button_array</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">tpm_infineon</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">tpm_tis</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">button</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">tpm</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">processor</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">it87</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hwmon_vid</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">coretemp</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">loop</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">autofs4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ext4</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">crc16</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">mbcache</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">jbd2</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">btrfs</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xor</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">raid6_pq</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">sr_mod</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">cdrom</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">sd_mod</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hid_generic</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">usbhid</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">hid</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">crc32c_intel</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ahci</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">libahci</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">r8169</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">psmouse</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">libata</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xhci_pci</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ehci_pci</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">xhci_hcd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">ehci_hcd</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">scsi_mod</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">mii</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">usbcore</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">usb_common</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">fan</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">thermal</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="n">fjes</span><span class="p">(</span><span class="n">E</span><span class="p">)</span> <span class="p">[</span><span class="n">last</span> <span class="nl">unloaded</span><span class="p">:</span> <span class="n">vboxdrv</span><span class="p">]</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405581</span><span class="p">]</span> <span class="nl">CPU</span><span class="p">:</span> <span class="mi">0</span> <span class="nl">PID</span><span class="p">:</span> <span class="mi">12046</span> <span class="nl">Comm</span><span class="p">:</span> <span class="n">rsync</span> <span class="nl">Tainted</span><span class="p">:</span> <span class="n">G</span> <span class="n">W</span> <span class="n">OE</span> <span class="mf">4.5.0</span><span class="o">-</span><span class="mi">1</span><span class="o">-</span><span class="n">amd64</span> <span class="err">#</span><span class="mi">1</span> <span class="n">Debian</span> <span class="mf">4.5.1</span><span class="o">-</span><span class="mi">1</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405583</span><span class="p">]</span> <span class="n">Hardware</span> <span class="nl">name</span><span class="p">:</span> <span class="n">Gigabyte</span> <span class="n">Technology</span> <span class="n">Co</span><span class="p">.,</span> <span class="n">Ltd</span><span class="p">.</span> <span class="n">H87M</span><span class="o">-</span><span class="n">HD3</span><span class="o">/</span><span class="n">H87M</span><span class="o">-</span><span class="n">HD3</span><span class="p">,</span> <span class="n">BIOS</span> <span class="n">F3</span> <span class="mo">05</span><span class="o">/</span><span class="mi">09</span><span class="o">/</span><span class="mi">2013</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405585</span><span class="p">]</span> <span class="mo">00000000000002</span><span class="mi">86</span> <span class="mf">000000008e92</span><span class="n">a6d5</span> <span class="n">ffffffff81307b65</span> <span class="mo">0000000000000000</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405589</span><span class="p">]</span> <span class="n">ffffffffc02f15b0</span> <span class="n">ffffffff8107905d</span> <span class="n">ffff8800a959e800</span> <span class="mo">0000000000004000</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405592</span><span class="p">]</span> <span class="n">ffff8800a959e800</span> <span class="mo">0000000000004000</span> <span class="mo">0000000000000002</span> <span class="n">ffffffffc02cfaf8</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405595</span><span class="p">]</span> <span class="n">Call</span> <span class="nl">Trace</span><span class="p">:</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405605</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff81307b65</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">dump_stack</span><span class="o">+</span><span class="mh">0x5c</span><span class="o">/</span><span class="mh">0x77</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405610</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff8107905d</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">warn_slowpath_common</span><span class="o">+</span><span class="mh">0x7d</span><span class="o">/</span><span class="mh">0xb0</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405630</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffffc02cfaf8</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">btrfs_qgroup_free_meta</span><span class="o">+</span><span class="mh">0x88</span><span class="o">/</span><span class="mh">0x90</span> <span class="p">[</span><span class="n">btrfs</span><span class="p">]</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405650</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffffc0268702</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">start_transaction</span><span class="o">+</span><span class="mh">0x3e2</span><span class="o">/</span><span class="mh">0x4a0</span> <span class="p">[</span><span class="n">btrfs</span><span class="p">]</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405668</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffffc026e507</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">btrfs_dirty_inode</span><span class="o">+</span><span class="mh">0x97</span><span class="o">/</span><span class="mh">0xc0</span> <span class="p">[</span><span class="n">btrfs</span><span class="p">]</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405672</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff81205538</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">touch_atime</span><span class="o">+</span><span class="mh">0xa8</span><span class="o">/</span><span class="mh">0xd0</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405676</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff8116d7bd</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">generic_file_read_iter</span><span class="o">+</span><span class="mh">0x63d</span><span class="o">/</span><span class="mh">0x790</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405681</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff811ee2b1</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">cp_new_stat</span><span class="o">+</span><span class="mh">0x151</span><span class="o">/</span><span class="mh">0x180</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405683</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff811e8913</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">new_sync_read</span><span class="o">+</span><span class="mh">0xa3</span><span class="o">/</span><span class="mh">0xe0</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405686</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff811e9101</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">vfs_read</span><span class="o">+</span><span class="mh">0x81</span><span class="o">/</span><span class="mh">0x120</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405689</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff811ea072</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">SyS_read</span><span class="o">+</span><span class="mh">0x52</span><span class="o">/</span><span class="mh">0xc0</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405693</span><span class="p">]</span> <span class="p">[</span><span class="o"><</span><span class="n">ffffffff815b6ab2</span><span class="o">></span><span class="p">]</span> <span class="o">?</span> <span class="n">system_call_fast_compare_end</span><span class="o">+</span><span class="mh">0xc</span><span class="o">/</span><span class="mh">0x67</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.405695</span><span class="p">]</span> <span class="o">---</span><span class="p">[</span> <span class="n">end</span> <span class="n">trace</span> <span class="mi">6</span><span class="n">c76a866f1f3e28c</span> <span class="p">]</span><span class="o">---</span>
<span class="nl">kernel</span><span class="p">:</span> <span class="p">[</span><span class="mf">52053.790081</span><span class="p">]</span> <span class="o">------------</span><span class="p">[</span> <span class="n">cut</span> <span class="n">here</span> <span class="p">]</span><span class="o">------------</span>
</pre></div>
<ul>
<li>At one point, when I disconnected a hard drive
that contained a mounted btrfs system, an instant hard reset of the machine (!).</li>
<li>Messed up filesystems where some operations would
take apparently forever (e.g., <code>subvolume delete</code>, on the target of the
transfer), during which mysterious processes like <code>btrfs-cleaner</code> and
<code>btrfs-transaction</code> were performing varying levels of CPU/IO, and the
lagging operation could not be aborted with SIGINT. I saw no way to
find out what the processes were trying to do.</li>
<li>Even weirder filesystems with which the entire machine started being unresponsive and
<a href="https://en.wikipedia.org/wiki/Out_of_memory">OOM-ing</a> for unclear
reasons, around 2 hours after they had been mounted. I eventually had
the idea of checking <code>slabtop</code>, which showed
that the kernel was filling the RAM (8 GB) with its own structures,
presumably because of some sisyphean operations that btrsync was
currently undertaking on them.</li>
<li>While the above happened, in other cases, it happened to me that <code>syslog</code>
got flooded with messages about btrsync, filling up my root partition.</li>
</ul>
<p>This is where I give up: even though I would very much like to have incremental
backups at the FS level, for now, I do not feel comfortable handing over my data
to a FS that suffers from this kind of problems. I know that, in principle, I
should try to report the bugs to developers and help fixing these issues, but sadly
I do not feel I can invest the time and effort to help debug an FS before I can
use it. Note that I did not even do very
ambitious things: essentially just snapshots, send, and receive, randomly
disconnecting the devices at various stages of the process. So maybe it could be
straightforward to reproduce the problems I ran into.</p>
<p>So I'm back to rsync for now, and I'll have to investigate incremental backup
programs that are smarter than rsync but do not rely on collaboration from the
FS, e.g., <a href="https://borgbackup.readthedocs.io/en/stable/">Borg</a>. Or maybe I could try <a href="https://en.wikipedia.org/wiki/ZFS">ZFS</a>...</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:btrfs_giving_up_troll">
<p>It's very funny to hear that btrfs must be
defragmented when you have heard for years the propaganda "only Microsoft file
systems must be defragmented, because they are inferior"... <a class="footnote-backref" href="#fnref:btrfs_giving_up_troll" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>a3nmMon, 18 Jul 2016 22:43:57 +0200tag:a3nm.net,2016-07-18:blog/btrfs_giving_up.htmlA coat-of-arms from pixel arthttps://a3nm.net/blog/coat_of_arms_pixel_art.html<p>My personal logo, which I use as a <a href="https://en.wikipedia.org/wiki/Favicon">favicon</a> on
my website and as an avatar, is a <a href="https://en.wikipedia.org/wiki/Pixel_art">pixel
art</a> representation of an 'a' in a
weird frame that spells out "3nm" in all directions:</p>
<p><img src="/logo.svg" alt="a3nm logo"
style="margin: auto; width: 50%; display: block; border: 1px solid #111144;" /></p>
<p>Its size is 16 pixels by 16 pixels.</p>
<p>I like <a href="https://en.wikipedia.org/wiki/Coat_of_arms">coats of arms</a>, so I thought
that it would be fun to try to draw one from my logo. The idea that I had is to use
<a href="https://en.wikipedia.org/wiki/Quartering_%28heraldry%29">quartering</a> to draw
the pixel art logo recursively using standard heraldic designs.</p>
<p>For starters, let us git rid of the messy part at the bottom of the shield to
get a nice square drawing area:</p>
<p><img src="coat_of_arms_pixel_art/blasonvide.svg" alt="empty coat of arms"
style="margin: auto; width: 50%; display: block;" /></p>
<p>This is described as follows in French (I will only be using French descriptions
as they are the only ones I know about):</p>
<div class="codehilite"><pre><span></span>D'argent à la champagne d'azur.
</pre></div>
<p>In the drawing above, I used a non-standard color for azure to match the pixel
art logo, and I used a <a href="https://commons.wikimedia.org/wiki/File:Blason_Vide_Moderne_3D.svg">modern
shield</a> to
get a more reasonable drawing area. I hope you don't mind. The fact that azure
is a colour and silver is a metal will ensure that we do not violate the <a href="https://en.wikipedia.org/wiki/Rule_of_tincture">rule
of tincture</a>.</p>
<p>Now, let us describe the actual pixel art logo, using recursive quarterings. A
complication is that simpler forms should be correctly described when we reach
them, for instance, a 4x4 design should be described as "parti" or "coupé"
<a href="https://en.wikipedia.org/wiki/Division_of_the_field">divisions</a> if applicable,
and if only one pixel is drawn differently from the three others, it is better
described as a
<a href="https://en.wikipedia.org/wiki/Ordinary_%28heraldry%29#Fixed_subordinaries">quarter</a>,
or "franc-quartier", whose position must be specified.</p>
<p>I used a small program to generate the correct description, and verified it by
drawing the resulting coat of arms by hand. Here it is, in French:</p>
<div class="codehilite_full"></div>
<div class="codehilite"><pre><span></span>Grand-écartelé :
au premier, écartelé :
au premier, contre-écartelé :
au premier, parti d'argent et d'azur,
au deuxième, parti d'azur et d'argent,
au troisième d'azur au franc-quartier d'argent à senestre,
au quatrième d'azur au franc-quartier d'argent,
au deuxième, contre-écartelé :
au premier d'azur,
au deuxième, parti d'argent et d'azur,
au troisième, coupé d'argent et d'azur,
au quatrième d'azur au franc-quartier d'argent,
au troisième, contre-écartelé :
au premier, coupé d'argent et d'azur,
au deuxième, parti d'argent et d'azur,
au troisième, coupé d'azur et d'argent,
au quatrième d'azur au franc-quartier d'argent,
au quatrième, contre-écartelé :
au premier d'argent au franc-quartier d'azur,
au deuxième, coupé d'argent et d'azur,
au troisième d'azur au franc-quartier d'argent à senestre et en pointe,
au quatrième, coupé d'azur et d'argent,
au deuxième, écartelé :
au premier, contre-écartelé :
au premier, parti d'argent et d'azur,
au deuxième, parti d'azur et d'argent,
au troisième d'azur au franc-quartier d'argent à senestre,
au quatrième, coupé d'argent et d'azur,
au deuxième, contre-écartelé :
au premier d'azur au franc-quartier d'argent à senestre et en pointe,
au deuxième, coupé d'argent et d'azur,
au troisième d'azur au franc-quartier d'argent à senestre,
au quatrième, coupé d'azur et d'argent,
au troisième, contre-écartelé :
au premier, coupé d'argent et d'azur,
au deuxième d'argent au franc-quartier d'azur à senestre,
au troisième, coupé d'azur et d'argent,
au quatrième d'argent,
au quatrième, contre-écartelé :
au premier, parti d'azur et d'argent,
au deuxième d'azur,
au troisième d'azur au franc-quartier d'argent à senestre,
au quatrième, coupé d'argent et d'azur,
au troisième, écartelé :
au premier, contre-écartelé :
au premier, coupé d'azur et d'argent,
au deuxième d'azur au franc-quartier d'argent en pointe,
au troisième d'azur,
au quatrième, parti d'argent et d'azur,
au deuxième, contre-écartelé :
au premier d'argent,
au deuxième d'azur,
au troisième d'argent au franc-quartier d'azur en pointe,
au quatrième, coupé d'azur et d'argent,
au troisième, contre-écartelé :
au premier, coupé d'argent et d'azur,
au deuxième d'azur au franc-quartier d'argent en pointe,
au troisième, coupé d'azur et d'argent,
au quatrième d'azur au franc-quartier d'argent,
au quatrième, contre-écartelé :
au premier, coupé d'azur et d'argent,
au deuxième d'azur au franc-quartier d'argent en pointe,
au troisième, parti d'argent et d'azur,
au quatrième, parti d'azur et d'argent,
au quatrième, écartelé :
au premier, parti :
au premier, coupé :
au premier d'azur,
au deuxième, écartelé d'azur et d'argent,
au deuxième d'argent,
au deuxième, contre-écartelé :
au premier d'azur au franc-quartier d'argent à senestre et en pointe,
au deuxième, coupé d'argent et d'azur,
au troisième, parti d'azur et d'argent,
au quatrième, coupé d'azur et d'argent,
au troisième, contre-écartelé :
au premier d'azur au franc-quartier d'argent à senestre et en pointe,
au deuxième, coupé d'azur et d'argent,
au troisième, parti d'azur et d'argent,
au quatrième d'azur,
au quatrième, contre-écartelé :
au premier d'azur au franc-quartier d'argent à senestre et en pointe,
au deuxième d'azur au franc-quartier d'argent en pointe,
au troisième, parti d'argent et d'azur,
au quatrième, parti d'azur et d'argent ;
à la champagne d'azur.
</pre></div>
<p>You can use the indentation to recursively match indented blocks of the code
above to squares following a kind of
<a href="https://en.wikipedia.org/wiki/Quadtree">quadtree</a> decomposition.
Here is the result:</p>
<p><img src="coat_of_arms_pixel_art/blason.svg" alt="my coat of arms"
style="margin: auto; width: 50%; display: block;" /></p>
<p>So my coat of arms is drawn from a pixel art logo, and has a textual description
which should hopefully follow (the letter of) the rules of the art, and should
allow any (sufficiently motivated) herald to reconstruct the design from the
text alone.</p>
<p>An direction for future work would be to design a general program to convert
arbitrary pixel art designs to textual descriptions of coats of arms. :) I
thought about it a bit, but it's trickier than it sounds if you want to use the
full power of known heraldic operators.</p>
<p><span class="update">Readers interested by heraldics and computer science may also be interested by
<a href="http://www.pps.univ-paris-diderot.fr/~eleph/">Pascal Manoury</a>'s work on drawing
coats of arms. The task studied there is to produce the graphical description of a coat
of arms given a (structured) textual description of its contents. Here is the
<a href="http://jfla.inria.fr/2010/actes/PDF/manoury.pdf">article</a> about this topic (in
French), as well as
<a href="http://jfla.inria.fr/2010/actes/PRESENTATIONS/manoury.pdf">slides</a> (in French),
and sample
<a href="http://www.pps.univ-paris-diderot.fr/~eleph/Recherche/Hrld/dbs.html">output</a>
(in French). Thanks to
<a href="https://twitter.com/Olive_Roussel">Olivier Roussel</a> for pointing this
out!</span></p>a3nmThu, 25 Feb 2016 11:16:27 +0100tag:a3nm.net,2016-02-25:blog/coat_of_arms_pixel_art.htmlEncrypt email to known GPG users with mutt using crypt_opportunistic_encrypthttps://a3nm.net/blog/mutt_crypt_opportunistic_encrypt.html<p>If you use <a href="http://www.mutt.org/">mutt</a> and <a href="https://www.gnupg.org/">GPG</a>, you
may want to say that messages sent to other GPG users should be encrypted by
default, and others should not.</p>
<p>This used to be surprisingly hacky to do, with the most common solution
apparently being a
<a href="http://tanguy.ortolo.eu/blog/article117/mutt-hook-encrypt">script</a> that listed
known GPG keys and added mutt
<a href="http://www.mutt.org/doc/manual/manual-4.html#ss4.4">hooks</a> to enable them. This
was ugly and it also didn't work well because it would try to encrypt messages
as soon as <em>some</em> recipient supported GPG, even when <em>all</em> recipients did not.</p>
<p>This post advertises a recent solution to this problem: the
<a href="http://www.mutt.org/doc/manual/#crypt-opportunistic-encrypt">crypt_opportunistic_encrypt</a> setting of mutt, which was
<a href="http://www.8t8.us/blog/2015/04/01/opportunistic-encrypt-committed.html">merged</a><sup id="fnref:mutt_crypt_opportunistic_encrypt_thanks"><a class="footnote-ref" href="#fn:mutt_crypt_opportunistic_encrypt_thanks" rel="footnote">1</a></sup>
in mutt version 1.5.24 (the one currently in Debian testing). This setting
allows you to do essentially what the hacky script did, but in a much cleaner
and simple way, also fixing the problem I mentioned.</p>
<p>I am currently using the setting in my <a href="/git/myconfig/tree/mutt/muttrc">mutt
config</a> and I quite happy about it. Here are
things to know when the setting is enabled:</p>
<ul>
<li>The choice to encrypt or not encrypt the message is toggled whenever the
recipients are edited, it's not only based on the initial recipients.</li>
<li>Encryption is chosen only if <em>all</em> recipients have a key.</li>
<li>You can always edit signing options or simply disable
encryption with the usual <code>pgp-menu</code> command ('p'). You can also disable
the opportunistic encryption setting for a single message in the <code>pgp-menu</code>
and you can then fall back to configuring encryption in the usual way.</li>
<li>Encryption is enabled as soon as the recipients have a GPG key that looks
reasonable (i.e., when I tested, it was not enabled for recipients where all
keys were either disabled or expired), but there is no
check<sup id="fnref:mutt_crypt_opportunistic_encrypt_security"><a class="footnote-ref" href="#fn:mutt_crypt_opportunistic_encrypt_security" rel="footnote">2</a></sup> to see whether
the key is known to be valid. If a recipient has no trusted key, you will
get the usual prompt to choose a key and confirm that you want to use the
key even though its validity is unknown.</li>
<li>GPG seems to get invoked for the purposes of the option, so, whenever gpg
decides to (presumably) check the trustdb, mutt may mysteriously hang. Just
be patient.</li>
</ul>
<div class="footnote">
<hr />
<ol>
<li id="fn:mutt_crypt_opportunistic_encrypt_thanks">
<p>Thanks a lot to
<a href="http://www.8t8.us/">Kevin</a> for developing and merging this! <a class="footnote-backref" href="#fnref:mutt_crypt_opportunistic_encrypt_thanks" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:mutt_crypt_opportunistic_encrypt_security">
<p>I think that this is quite
reasonable, because in practice active attacks with GPG are not a huge problem,
much less than the problem that few people are using GPG. I think it
especially makes sense in combination with GPG's recent support of
<a href="https://lists.gnupg.org/pipermail/gnupg-announce/2015q4/000381.html">trust on first use</a>
(TOFU) to make it less painful to use. <a class="footnote-backref" href="#fnref:mutt_crypt_opportunistic_encrypt_security" rev="footnote" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
</ol>
</div>a3nmMon, 22 Feb 2016 14:53:57 +0100tag:a3nm.net,2016-02-22:blog/mutt_crypt_opportunistic_encrypt.htmlSelf-hosted, server-side MathJaxhttps://a3nm.net/blog/selfhost_mathjax.html<p>I use <a href="https://www.mathjax.org/">MathJax</a> on my website to render math equations
to HTML. The <a href="https://docs.mathjax.org/en/v2.6-latest/start.html">standard way</a>
to use MathJax is to use JavaScript so that visitors will get it from their
<a href="https://en.wikipedia.org/wiki/Content_Delivery_Network">CDN</a>. While this is
simpler and also a good idea for caching, it has drawbacks which I did not find
acceptable:</p>
<ul>
<li>It means that the MathJax CDN may be pinged whenever a visitor loads a page,
which is bad for privacy.</li>
<li>It makes your website's security dependent on that of the CDN: if the CDN starts
distributing malicious JS (i.e., MathJax turns evil or it gets hacked),
then your visitors will be getting them.</li>
<li>It renders math in the browser using JavaScript. This is jarring (as the page
jumps around while rendering is done), and I find it esthetically
unpleasant. All of this website is static and pre-generated on my machine, I
don't see why math rendering would be an exception. I find static websites
preferable in terms of deployability, security, and elegance.</li>
</ul>
<p>This post is just to explain how to render MathJax when generating static pages,
using <a href="https://github.com/mathjax/MathJax-node">MathJax-node</a>. As I wanted to
play with <a href="https://www.docker.com/">Docker</a>, and didn't want to install Node or
run the code directly on my real machine, I will also explain how to set up the
environment in a Docker container, but there's nothing forcing you to do that.
:)</p>
<p>I am now using this setup on this website, so all math should now be served with
server-side rendering, without requests to third-party CDNs. (In fact,
this removes what was essentially the only use of JavaScript on this site.)</p>
<h2>Setting up a mirror of the fonts</h2>
<p>While we won't need to serve the MathJax JavaScript code to readers, we will
need to serve them the fonts used by MathJax.</p>
<p>Fortunately, on Debian systems, these fonts are already packaged as
<code>fonts-mathjax</code> and <code>fonts-mathjax-extras</code>, so you can just rely on the package
manager to retrieve them and keep them up to date. The fonts are installed in
<code>/usr/share/javascript/mathjax/</code>, so you just have to configure your Web server
to serve this folder. I serve it as
<a href="https://a3nm.net/mathjax/">a3nm.net/mathjax</a>. It's preferable to serve it from
the same domain that you will otherwise use, otherwise it's necessary to jump
through additional hoops because of the same-origin policy: see <a href="https://mathjax.readthedocs.org/en/latest/installation.html#cross-domain-linking">an
explanation
here</a>.</p>
<h2>Installing MathJax-node</h2>
<p>I installed MathJax-node in a Docker image, and as I was paranoid I also
generated my own base image for the underlying system. Feel free to simplify the
instructions if you don't need to do any of this.</p>
<p>I'm using an amd64 Debian system. I installed Docker as <code>docker.io</code> (packaged
with Debian), added myself to the <code>docker</code> group, logged out and logged in. I
tweaked Docker by editing <code>/etc/default/docker</code> and symlinking <code>/var/lib/docker</code>
to move its files to a partition with more disk space.</p>
<p>I created the base system by issuing the following. Note that we will need
Debian testing to be able to run <code>mathjax-node</code>, as otherwise the packaged
version of Node is too old:</p>
<div class="codehilite"><pre><span></span>mkdir testing
sudo debootstrap testing testing/
sudo tar -C testing/ -c . <span class="p">|</span> docker import - my-debian-testing
</pre></div>
<p>Here is the <code>Dockerfile</code>:</p>
<div class="codehilite"><pre><span></span><span class="k">FROM</span><span class="s"> my-debian-testing:latest</span>
<span class="k">RUN</span> apt-get -y update <span class="o">&&</span> apt-get install -y npm nodejs-legacy <span class="o">&&</span> apt-get clean
<span class="k">RUN</span> npm install mathjax-node
<span class="k">RUN</span> npm install cssstyle
<span class="k">CMD</span><span class="s"> ["bash"]</span>
</pre></div>
<p>In the folder of the file, issue:</p>
<div class="codehilite"><pre><span></span>docker build -t my-mathjax .
</pre></div>
<p>You can now use the image by starting a container, let's call it <code>my-container</code>:</p>
<div class="codehilite"><pre><span></span>docker run -di --name<span class="o">=</span>my-container my-mathjax bash >/dev/null
</pre></div>
<p>And you can then apply <code>page2html</code> by piping your HTML code in the following
invocation:</p>
<div class="codehilite"><pre><span></span>docker <span class="nb">exec</span> -i my-mathjax node_modules/mathjax-node/bin/page2html <span class="se">\</span>
--fontURL https://a3nm.net/mathjax/fonts/HTML-CSS<span class="s2">"</span>
</pre></div>
<p>Replace the <code>fontURL</code> parameter by the URL you are serving the MathJax fonts.</p>
<p><span class="update">Another possibility is to use <code>page2svg</code> to render the math
to SVG instead of HTML markup. However, this means that text-based browsers will
not be able to see it.</span></p>
<p>The actual code that I use is
<a href="https://a3nm.net/git/mybin/tree/addmathjax">here</a>. <span class="update">I also increase the size of
math by adding the following CSS as indicated
<a href="https://github.com/mathjax/MathJax-node/issues/204#issuecomment-208351504">here</a>:</span></p>
<div class="codehilite"><pre><span></span><span class="nc">.mjx-chtml</span> <span class="p">{</span><span class="nb">font-size</span><span class="o">:</span> <span class="m">2.26ex</span> <span class="o">!</span> <span class="n">important</span><span class="p">}</span>
<span class="nc">.mjx-chtml</span> <span class="nc">.mjx-chtml</span> <span class="p">{</span><span class="nb">font-size</span><span class="o">:</span> <span class="nb">inherit</span> <span class="o">!</span> <span class="n">important</span><span class="p">}</span>
</pre></div>
<h2>Marking up MathJax</h2>
<p>I use Markdown to write Web pages.
I use <a href="https://github.com/mitya57/python-markdown-math">python-markdown-math</a> to
convert math notation from a dollar-based notation in Markdown to HTML <code>span</code>s with
the right <code>class</code>es (<code>class="tex"</code> or <code>class="math"</code>). To use
python-markdown-math with the server-side setup, simply prevent it
from adding the MathJax <code>script</code> boilerplate. I also use the <code>render_to_span</code> config
parameter to ensure that no <code>script</code> is being generated.</p>
<p>To prepare the MathJax afterwards, you
should be careful that the command of the previous section needs to apply to the
<em>entire</em> HTML document, <em>not</em> just the HTML markup generated from Markdown
before applying a template. Indeed, you will see that modifies the <code>head</code>
element as well.</p>
<h2>Performance</h2>
<p>On modern hardware with this setup, it takes about one second to process an HTML
page (even when there is no math in it). It takes a few seconds to process HTML
pages with real markup such as <a href="/work/research/questions">this one</a>.</p>
<p>Here's an example formula to see how it works: it should look the same as any
regular MathJax formula, but without the blinking caused by JavaScript rendering:
<span class="math">\(\pi(I) = \Big(\prod_{F \in I} \pi(F)\Big) \times \Big(\prod_{F \in J
\backslash I} (1 - \pi(F))\Big)\)</span>.</p>a3nmSat, 20 Feb 2016 23:19:31 +0100tag:a3nm.net,2016-02-20:blog/selfhost_mathjax.htmlSummary on (hyper)graph tractability parametershttps://a3nm.net/blog/graph_tractability.html<p>For my PhD research, I had to investigate various notions of (hyper)graph tractability,
such as treewidth, cliquewidth, pathwidth, etc. Here is a very terse summary of
what I have found about them. It is mostly my personal summary of reading
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">this survey</a> and some other
papers, but maybe it may interest others.</p>
<p>To give the broad context: computer scientists are interested in solving
problems on
<a href="https://en.wikipedia.org/wiki/Graph_%28mathematics%29">graphs</a>, e.g., given a
graph, does it have a
specific property (for instance,
can it be
<a href="https://en.wikipedia.org/wiki/Planar_graph">drawn without edge crossings</a>,
can it be
<a href="https://en.wikipedia.org/wiki/Graph_coloring">colored with 3 colors</a>, etc.).
Some of these problems are known to be
<a href="https://en.wikipedia.org/wiki/NP-hard">intractable</a> in the sense of
<a href="https://en.wikipedia.org/wiki/Computational_complexity_theory">complexity theory</a>,
which means that there is probably no fast algorithm to solve them.
However, many of those hard problems can be solved efficiently in the specific
case of graphs that are
<a href="https://en.wikipedia.org/wiki/Tree_%28graph_theory%29#forest">forests</a>, i.e., that do
not have
<a href="https://en.wikipedia.org/wiki/Cycle_%28graph_theory%29">cycles</a>.</p>
<p>Graph theorists have tried to understand what makes trees tractable, and to
extend the notion of <em>acyclicity</em> ("being a forest") in two broad respects.
First, by identifying broader notions for graphs, which are <em>parameterized</em>:
a parameter <span class="math">\(k\)</span> indicates how much the graph deviates from acyclicity, and the
notion should collapse to acyclicity for small <span class="math">\(k\)</span>. The hope is then that,
for fixed <span class="math">\(k\)</span> (i.e., for graphs that are not-acyclic only by a small margin), we
can still enjoy tractability, for instance in the sense of <a href="https://en.wikipedia.org/wiki/Parameterized_complexity">parameterized
complexity</a>.
Second, theorists have tried to extend acyclicity
from graphs to the more expressive formalism of
<a href="https://en.wikipedia.org/wiki/Hypergraph">hypergraphs</a>, i.e., graphs where
edges can connect an arbitrary number of vertices.</p>
<p><span class="update">In all this post except where <a href="#graph_tractability_directed">explicitly stated
otherwise</a>, we consider <em>undirected</em> graphs, i.e.,
a pair <span class="math">\((V, E)\)</span> of a set of <em>vertices</em> and a set of <em>edges</em> which are pairs of
vertices.</a></p>
<p><strong>Roadmap:</strong></p>
<ul>
<li><a href="#graph_tractability_tw">Section 1</a> presents treewidth,
branchwidth (essentially equivalent), and pathwidth (more restrictive, i.e., a
graph's pathwidth is more than its treewidth), <span class="update">and
treedepth, which is more restrictive than pathwidth in the same sense</a>.</li>
<li><a href="#graph_tractability_rw">Section 2</a> presents rankwidth and cliquewidth
(equivalent, and less restrictive than the previous ones).</li>
<li><a href="#graph_tractability_preserve">Section 3</a> discusses preservation under subgraphs,
minors, and other operations.</li>
<li><a href="#graph_tractability_hyper">Section 4</a> discusses extended definitions for
hypergraphs.</li>
<li><a href="#graph_tractability_complexity">Section 5</a> discusses the complexity of
computing these parameters.</li>
<li><a href="#graph_tractability_logical">Section 6</a> discusses their applicability for the
decidability of logical theories, the tractability of model checking and
other such problems for expressive languages.</li>
<li><a href="#graph_tractability_csp">Section 7</a> studies their use for less expressive
languages: the problems of CSP, query evaluation and homomorphisms.</li>
<li><a href="#graph_tractability_posets">Section 8</a> is an appendix with a remark about
partial orders.</li>
</ul>
<p>All links to scientific works are
<a href="https://en.wikipedia.org/wiki/Open_access">open-access</a>, i.e., available
without a subscription. I give them as direct links, but I also give the
<a href="https://en.wikipedia.org/wiki/Digital_Object_Identifier">DOI</a> of each link <a href="#graph_tractability_doi">at
the end</a>.</p>
<p><strong>Warning:</strong>
Please be aware
that this summary are my personal notes: it may contain errors and should not be
taken at face value. Please let me know if you find any bugs.</p>
<p><strong>Acknowledgements:</strong> Thanks to <a href="http://pierre.senellart.com/">Pierre
Senellart</a>,
Mikaël Monet and <a href="http://robinmorisset.fr/">Robin Morisset</a> for proofreading and comments.</p>
<h2><a id="graph_tractability_tw"></a> Treewidth, pathwidth, branchwidth</h2>
<h3>Treewidth (tw)</h3>
<p><a href="https://en.wikipedia.org/wiki/Treewidth">Treewidth</a> is the most common measure,
and can be defined in multiple different ways.
The <em>treewidth</em> of a graph <span class="math">\(G\)</span> is the smallest <span class="math">\(k\)</span> such that it admits a <em>tree
decomposition</em> of width <span class="math">\(k\)</span> in one of the following senses:</p>
<ul>
<li>
<p><strong>Formally:</strong> we can associate a
<a href="https://en.wikipedia.org/wiki/Tree_%28graph_theory%29">tree</a> <span class="math">\(T\)</span> to <span class="math">\(G\)</span> (called
the <em>tree decomposition</em>), with each node of <span class="math">\(T\)</span> (called <em>bag</em>) labeled by a
subset of the graph vertices, such that:</p>
<ul>
<li>for each edge of <span class="math">\(G\)</span>, its endpoints co-occur in some bag of <span class="math">\(T\)</span></li>
<li>for each vertex of <span class="math">\(G\)</span>, the nodes of <span class="math">\(T\)</span> where it occurs form a
connected subtree in <span class="math">\(T\)</span></li>
</ul>
<p>The <em>width</em> of the tree decomposition <span class="math">\(T\)</span> is <span class="math">\(k-1\)</span> where <span class="math">\(k\)</span> is the maximal
number of vertices in a bag of <span class="math">\(T\)</span>.</p>
<p>While tree decompositions are not oriented, it is often convenient to
pick a root and see them as rooted trees.</p>
</li>
<li>
<p><strong>As a decomposition scheme.</strong> Trees can be decomposed by picking a
<em>separator</em> formed of two adjacent
vertices, removing the edge between them, and decomposing
recursively each connected component: in each component, you can pick a
separator that includes the vertices of the parent separator which are also in
that component.</p>
<p>As a generalization, graphs of treewidth <span class="math">\(k\)</span> can
be decomposed by picking a <em>separator</em> of <span class="math">\(k+1\)</span> vertices, removing edges between
them, and decomposing recursively each connected component,
requiring that each component's separator includes the vertices
of the parent separator which are part of the component.
The tree of the separators chosen in this process is a tree decomposition of
the instance, because the separators have the right size, cover all edges,
and whenever a vertex occurs in a separator it will occur in all descendent
separators until we reach a component where the vertex no longer occurs.</p>
<p>Conversely, when looking at any non-root bag <span class="math">\(b\)</span> of a tree decomposition <span class="math">\(T\)</span>, considering
the subgraph <span class="math">\(G_1\)</span> of the decomposed graph formed of the vertices occuring
in <span class="math">\(b\)</span> and its descendants (the subtree <span class="math">\(T_b\)</span> of <span class="math">\(b\)</span> rooted at <span class="math">\(T\)</span>), and
<span class="math">\(G_2\)</span> the subgraph of the vertices occurring in the other bags, the common
vertices between <span class="math">\(G_1\)</span> and <span class="math">\(G_2\)</span> are those shared between <span class="math">\(b\)</span> and its
parent (often called an <em>interface</em>), and removing those in <span class="math">\(G\)</span> disconnects <span class="math">\(G_1\)</span> and <span class="math">\(G_2\)</span> (any other
path connecting them could not be legally reflected in the decomposition).
So <span class="math">\(T_b\)</span> can be recursively understood as a tree decomposition of <span class="math">\(G_1\)</span>,
which has been disconnected from the rest of <span class="math">\(G\)</span>.</p>
<p>This <a href="http://cstheory.stackexchange.com/a/5040">explanation</a> with pictures
may help you understand what I mean.</p>
</li>
<li>
<p><strong>As a <a href="https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms">divide and
conquer</a>
scheme.</strong>
Many problems on a rooted tree can be solved by a <a href="https://en.wikipedia.org/wiki/Dynamic_programming">dynamic
programming algorithm</a>
that solves the problem on any subtree given the solution to its child
subtrees; this is usually just thought of as a bottom-up computation. In
graphs of treewidth <span class="math">\(k\)</span>, following the above scheme (or a rooted tree
decomposition) gives you a way to solve problems on the graph with a similar
divide-and-conquer dynamic programming scheme.</p>
<p>Again, this is nicely covered by the explanation linked above.</p>
</li>
<li>
<p><strong>As a <a href="https://en.wikipedia.org/wiki/Pursuit-evasion">pursuit-evasion game</a>,</strong>
where "cops" use a decomposition of the graph to corner and catch a
"robber". For more details, see
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>,
Section 5.7.</p>
</li>
</ul>
<p>Forests have treewidth <span class="math">\(1\)</span> (so "having treewidth <span class="math">\(1\)</span>" means "being acyclic"),
cycles have treewidth <span class="math">\(2\)</span>,
<a href="https://en.wikipedia.org/wiki/Clique_%28graph_theory%29">cliques</a> with <span class="math">\(k\)</span>
vertices have treewidth <span class="math">\(k-1\)</span>, but
<a href="https://en.wikipedia.org/wiki/Grid_%28graph_theory%29">grids</a> illustrate that
graphs may be <a href="https://en.wikipedia.org/wiki/Planar_graph">planar</a> but have a
high treewidth: a <span class="math">\(k\)</span> by <span class="math">\(k\)</span> grid has treewidth <span class="math">\(k\)</span>.</p>
<h3>Pathwidth (pw)</h3>
<p><em><a href="https://en.wikipedia.org/wiki/Pathwidth">Pathwidth</a></em>
is a variant of treewidth where the underlying tree in the formal
definition is required to be a <a href="https://en.wikipedia.org/wiki/Path_graph">path
graph</a> rather than a general tree. It has many
<a href="https://en.wikipedia.org/wiki/Pathwidth#Alternative_characterizations">alternative
characterizations</a>,
in particular in terms of overlapping intervals.</p>
<p>I won't be coming back to pathwidth later, but to contrast it with treewidth,
for any graph <span class="math">\(G\)</span>:</p>
<ul>
<li><span class="math">\(\text{tw}(G) \leq \text{pw}(G)\)</span>: immediate as one notion is more restrictive
than the other;</li>
<li><span class="math">\(\text{pw}(G) = O(\text{tw}(G) \log |G|)\)</span>: see
<a href="http://www.sciencedirect.com/science/article/pii/S0304397597002284">bodlaender1998partial</a>, Corollary 24.</li>
</ul>
<p>So "having bounded pw" is strictly more restrictive than "having bounded tw".</p>
<h3>Branchwidth (bw)</h3>
<p><em><a href="https://en.wikipedia.org/wiki/Branch-decomposition">Branchwidth</a></em> can be defined
as follows. Let <span class="math">\(G = (V, E)\)</span> be a graph. Given a partition of its edges <span class="math">\(E = E_1
\sqcup E_2\)</span>, call its <em>weight</em> the number of vertices incident both to an edge
in <span class="math">\(E_1\)</span> and an edge in <span class="math">\(E_2\)</span>. A <em>branch decomposition</em> of width <span class="math">\(k\)</span> of <span class="math">\(G\)</span> is a
subcubic tree (nodes have degree either 1 or 3)
where each <em>leaf</em> is labeled <em>bijectively</em> by an <em>edge</em> of <span class="math">\(G\)</span>, and for each edge of the
tree, considering <span class="math">\(E_1 \sqcup E_2\)</span> where <span class="math">\(E_1\)</span> and <span class="math">\(E_2\)</span> are the edges that
annotate each half of the tree, the weight of this partition is at most <span class="math">\(k\)</span>.</p>
<p>Branchwidth is less used than treewidth in computer science, but it has the nice
property that a variant of the definition yields
the notion of <em>rankwidth</em> (see <a href="#graph_tractability_rw">later</a>). Further, it generalizes to
<em>hypergraphs</em> (see <a href="#graph_tractability_hbw">later</a>), and it generalizes to
<a href="https://en.wikipedia.org/wiki/Matroid">matroids</a> (I won't give more details).</p>
<p><a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>
(Section 3.1.1) gives a description<sup id="fnref:graph_tractability_bw2"><a class="footnote-ref" href="#fn:graph_tractability_bw2" rel="footnote">1</a></sup> of graphs of bw
<span class="math">\(\leq 2\)</span>.
Further, from
<a href="http://www.sciencedirect.com/science/article/pii/009589569190061N">robertson1991graph10</a>,
cited and proved in <a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>,
Theorem 3.1, we have, for any graph <span class="math">\(G\)</span> with branchwidth <span class="math">\(>1\)</span>: <span class="math">\(\text{bw}(G)
\leq \text{tw}(G)+1 \leq \lfloor 1.5 \cdot \text{bw}(G) \rfloor\)</span>. Hence, "having
bounded tw" and "having bounded bw" are equivalent.</p>
<h3><a id="graph_tractability_treedepth"></a> Treedepth</h3>
<p><span class="update">This is an addition to the original post</a></p>
<p><em><a href="https://en.wikipedia.org/wiki/Tree-depth">Treedepth</a></em> is defined as follows. An
<em>elimination forest</em> <span class="math">\(F\)</span> of a graph <span class="math">\(G = (V, E)\)</span> is a forest (i.e., a collection of
rooted trees) on <span class="math">\(V\)</span> that ensures that for any <span class="math">\(\{x, y\} \in E\)</span>, one of the
nodes for <span class="math">\(x\)</span> and <span class="math">\(y\)</span> in <span class="math">\(F\)</span> is an ancestor of the other in <span class="math">\(F\)</span> (or, equivalently,
there is a path from the root of <span class="math">\(F\)</span> to a leaf that covers both <span class="math">\(x\)</span> and <span class="math">\(y\)</span>).
The <em>depth</em> of an
elimination forest <span class="math">\(F\)</span> is the height of <span class="math">\(F\)</span> in the standard sense (i.e., the maximal height
of a tree of <span class="math">\(F\)</span>). The <em>treedepth</em> of <span class="math">\(G\)</span> is the minimal depth <span class="math">\(d\)</span> such that
<span class="math">\(G\)</span> has an elimination forest <span class="math">\(F\)</span> of depth <span class="math">\(d\)</span>.</p>
<p>I will not describe the notion of treedepth in more detail, but, to connect it with the
previous notions, we know, by Lemma 11 of
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.29.7198">bodlaender1995approximating</a>,
that, for any graph <span class="math">\(G\)</span>, we have <span class="math">\(\text{pw}(G) \leq \text{td}(G)\)</span>. However,
<a href="https://en.wikipedia.org/wiki/Path_graph">path graphs</a> have treedepth which is logarithmic in their size (with the
elimination forest given as the tree of a <a href="https://en.wikipedia.org/wiki/Binary_search_algorithm">binary
search</a>), but have
constant pathwidth.
So "having bounded td" is strictly more restrictive than "having bounded pw"
which is strictly more restrictive than "having bounded tw".</p>
<h2><a id="graph_tractability_rw"></a> Rankwidth and cliquewidth</h2>
<h3>Rankwidth (rw)</h3>
<p><em>Rankwidth</em> is defined just like branchwidth, except that we consider <em>vertex</em>
partitions <span class="math">\(V = V_1 \sqcup V_2\)</span>, whose weight is the
<a href="https://en.wikipedia.org/wiki/Rank_%28linear_algebra%29">rank</a> of the
<a href="https://en.wikipedia.org/wiki/Adjacency_matrix">adjacency matrix</a> from <span class="math">\(V_1\)</span> to
<span class="math">\(V_2\)</span> (taken as a
<a href="https://en.wikipedia.org/wiki/Matrix_%28mathematics%29#Submatrix">submatrix</a> of
the full graph's adjacency matrix): and we consider subcubic trees where leaves are
labeled by graph <em>vertices</em> rather than graph <em>edges</em>.</p>
<p>Rankwidth is less than branchwidth: <span class="math">\(\text{rw}(G) \leq \text{max}(1,
\text{bw}(G))\)</span>
as shown in <a href="http://mathsci.kaist.ac.kr/~sangil/pdf/2006incidencerev.pdf">oum2007rank</a>.
Hence, "having bounded bw" implies "having bounded rw".</p>
<p>Graphs with rankwidth 1 are the <a href="https://en.wikipedia.org/wiki/Distance-hereditary_graph">distance-hereditary
graphs</a>,
as shown in <a href="http://mathsci.kaist.ac.kr/~sangil/pdf/vertexminor-revision.pdf">oum2005rank</a>.</p>
<h3>Cliquewidth (cw)</h3>
<p>A <em>clique decomposition</em> of width <span class="math">\(k\)</span>, or <span class="math">\(k\)</span>-expression, in an expression over
the following operations, <span class="math">\(i\)</span> and <span class="math">\(j\)</span>
denoting any colors in
<span class="math">\(\{1, \ldots, k\}\)</span>:</p>
<ul>
<li>create the graph with one isolated vertex labeled by <span class="math">\(i\)</span></li>
<li>change all vertices of color <span class="math">\(i\)</span> to color <span class="math">\(j\)</span></li>
<li>connect all vertices of color <span class="math">\(i\)</span> to those of color <span class="math">\(j\)</span> (with <span class="math">\(j \neq i\)</span>, so no
self-loops)</li>
<li>take the disjoint union of two graphs constructed by such an expression</li>
</ul>
<p>A graph has <em>cliquewidth</em> <span class="math">\(k\)</span> if some coloring of it can be obtained by a clique
decomposition.</p>
<p>Graphs with cliquewidth <span class="math">\(1\)</span> are those with no edges, and graphs with cliquewidth
<span class="math">\(2\)</span> are the <a href="https://en.wikipedia.org/wiki/Cograph">cographs</a>.
The <span class="math">\(k\)</span> by <span class="math">\(k\)</span> grid has cliquewidth <span class="math">\(k+1\)</span> by
(<a href="http://www.researchgate.net/publication/220181029_On_the_Clique-Width_of_Some_Perfect_Graph_Classes">golumbic2000clique</a>).</p>
<p>Cliquewidth can be connected to the <a href="https://en.wikipedia.org/wiki/Modular_decomposition">modular
decomposition</a> of graphs.
Further, there are variants such as <em>symmetric cliquewidth</em>, with "bounded cw" equivalent
to "bounded scw", see
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, section
4.1.3.</p>
<p>Cliquewidth is connected to rankwidth
(<a href="http://www.sciencedirect.com/science/article/pii/S0095895605001528">oum2006approximating</a>):
<span class="math">\(\text{rw}(G) \leq \text{cw}(G) \leq 2^{1 + \text{rw}(G)} - 1\)</span>. Hence, "having bounded
cw" and "having bounded rw" are equivalent, though the rank-width bound can be
exponentially larger.</p>
<p>Cliquewidth is connected to treewidth: we have <span class="math">\(\text{cw}(G) \leq 3 \cdot
2^{\text{tw}(G)-1}\)</span>
by <a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a><sup id="fnref:graph_tractability_corneil"><a class="footnote-ref" href="#fn:graph_tractability_corneil" rel="footnote">2</a></sup>,
section 4.2.6.
Hence, "having bounded tw" implies "having bounded cw", though the bound may
again be
exponential.
Conversely, <span class="math">\(\text{tw}(G)\)</span> can be bounded as a function of <span class="math">\(\text{cw}(G)\)</span> and of
the <em>degree</em> of <span class="math">\(G\)</span>
(<a href="http://www.sciencedirect.com/science/article/pii/S0166218X08003351">kaminski2009recent</a>, Proposition 2 a),
so "having bounded cw" and "having bounded tw" are
<em>equivalent</em> on graph families of bounded degree. The dependence on degree
disappears for graph families that exclude any fixed graph as a minor
(Proposition 2 b).</p>
<h2><a id="graph_tractability_preserve"></a> Preservation under graph operations</h2>
<h3>Subgraphs and induced subgraphs</h3>
<p>A <a href="https://en.wikipedia.org/wiki/Glossary_of_graph_theory#Subgraphs">subgraph</a>
of a graph <span class="math">\(G\)</span> is obtained by keeping a subset of the edges and vertices of <span class="math">\(G\)</span>.
Further, it is an <em>induced subgraph</em> if the edges kept are exactly the
restriction of those of <span class="math">\(G\)</span> to the kept vertices (i.e., no edge between kept
vertices was removed).</p>
<p>A property is <em>S-closed</em> (resp. <em>I-closed</em>) if, when a graph has it,
every subgraph (resp. induced subgraph) also does.</p>
<h3>Minors and topological minors</h3>
<p>A <em><a href="https://en.wikipedia.org/wiki/Graph_minor">minor</a></em> of a graph can be obtained
from that graph by removing edges and vertices and <a href="https://en.wikipedia.org/wiki/Edge_contraction">contracting
edges</a>. Alternatively, it is
witnessed by mapping the vertices <span class="math">\(v\)</span>
of the minor <span class="math">\(G'\)</span> to disjoint subsets
<span class="math">\(s(v)\)</span> of vertices of the graph <span class="math">\(G\)</span>, and mapping each edge <span class="math">\((u, v)\)</span> of <span class="math">\(G'\)</span> to an edge between
<span class="math">\(s(u)\)</span> and <span class="math">\(s(v)\)</span> in <span class="math">\(G\)</span>.</p>
<p>A
<em><a href="https://en.wikipedia.org/wiki/Graph_minor">topological minor</a></em>
maps each vertex <span class="math">\(v\)</span> of <span class="math">\(G'\)</span> to a
single vertex <span class="math">\(s(v)\)</span> of <span class="math">\(G\)</span>, and maps edges <span class="math">\((u, v)\)</span> of <span class="math">\(G'\)</span> to <em>vertex-disjoint</em>
paths from <span class="math">\(s(u)\)</span> to <span class="math">\(s(v)\)</span> in <span class="math">\(G\)</span>: equivalently, a
<a href="https://en.wikipedia.org/wiki/Homeomorphism_(graph_theory)#Subdivision_and_smoothing">subdivision</a>
of <span class="math">\(G'\)</span> is isomorphic to a subgraph of <span class="math">\(G\)</span>.
Clearly if <span class="math">\(G'\)</span> is a topological minor of <span class="math">\(G\)</span> then it is a minor of <span class="math">\(G\)</span>.</p>
<p>We define <em>M-closed</em> and <em>T-closed</em> for minors and topological minors as we defined
S-closed and I-closed.</p>
<p>In summary, from
<a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a><sup id="fnref:graph_tractability_makowsky"><a class="footnote-ref" href="#fn:graph_tractability_makowsky" rel="footnote">3</a></sup>:</p>
<ul>
<li>M-closed implies T-closed, S-closed, I-closed;</li>
<li>T-closed implies S-closed, I-closed;</li>
<li>S-closed implies I-closed;</li>
<li>No other implication holds.</li>
</ul>
<h3>Monotonicity of our definitions</h3>
<p>Standard graph acyclicity is M-closed.
Hence, it is natural to wonder whether our other parameters also are.</p>
<ul>
<li>"having treewidth <span class="math">\(\leq k\)</span>" is M-closed (as can be seen by applying deletions
and merges to the tree decomposition).</li>
<li>"having pathwidth <span class="math">\(\leq k\)</span>" is M-closed (same argument).</li>
<li>"having branchwidth <span class="math">\(\leq k\)</span>" is M-closed
(<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, Prop
3.2).</li>
<li>"having cliquewidth <span class="math">\(\leq k\)</span>" is I-closed
<a href="http://www.labri.fr/perso/courcell/CoursMaster/BC-Olariu(2000).pdf">courcelle1990upper</a>
but obviously not S-closed (<a href="https://en.wikipedia.org/wiki/Complete_graph">complete graphs</a> have cliquewidth <span class="math">\(\leq 2\)</span> but their
subgraphs cover all graphs)
nor T-closed.</li>
<li>"having rankwidth <span class="math">\(\leq k\)</span>" is I-closed but not S-closed for the same
reasons.</li>
</ul>
<p>Rankwidth is, however, preserved by the graph operation of <em>vertex-minor</em>
(<a href="http://mathsci.kaist.ac.kr/~sangil/pdf/vertexminor-revision.pdf">oum2005rank</a>).</p>
<h3>Other operations</h3>
<p>Cliquewidth and rankwidth behave well under graph <em>complementation</em>: complementing
can at most double the cw, and adds or removes at most <span class="math">\(1\)</span> to the rw (quoted in
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, section 4.2.1).
By contrast, no such bounds are possible for treewidth and hence rankwidth
(consider the graphs with no edges).</p>
<p>Treewidth, branchwidth, pathwidth, cliquewidth, rankwidth, can be computed on a
graph with multiple <em>connected components</em> as the max of the same measure over each of the
connected components.</p>
<p><em>Adding</em> or <em>deleting</em> <span class="math">\(k\)</span> vertices or <span class="math">\(k\)</span> edges can only make rankwidth
and cliquewidth vary by at most <span class="math">\(k\)</span>
(<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>). The same
holds for treewidth (immediate as each vertex addition in a tree
decomposition can only affect the width by at most 1).</p>
<p>For S-closed families, "having bounded cw" and "having bounded tw" are
equivalent
(<a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a>,
Proposition 7, attributed to courcelle1995logical which seems unavailable
online).</p>
<h2><a id="graph_tractability_hyper"></a> Hypergraphs</h2>
<p><em>Hypergraphs</em> generalize graphs by allowing <em>hyperedges</em> that include an arbitrary number
of vertices.</p>
<p>We will sometimes consider <em>instances</em>, whose hyperedges (called <em>facts</em>) are
allowed to have a label (called the <em>predicate</em> or <em>relation</em>, which has a fixed
arity) and where the occurrences of vertices in facts may be labeled as well:
a fact is written <span class="math">\(A(a_1, \ldots, a_n)\)</span>, where <span class="math">\(A\)</span> is the predicate, <span class="math">\(n\)</span> is the
arity, and the <span class="math">\(a_i\)</span> need not be all
different. Hence, an instance in logical terms is a
<a href="https://en.wikipedia.org/wiki/Structure_%28mathematical_logic%29">structure</a>
for some
<a href="https://en.wikipedia.org/wiki/Signature_%28logic%29">relational signature</a>.
In this context it is natural to assume that the maximal <em>arity</em> (number of
vertices per hyperedge) is bounded by a constant, though this assumption is not
usually done when working on vanilla hypergraphs.</p>
<h3>From hypergraphs to graphs</h3>
<p>The following discussion of how to get from a hypergraph to a graph is from
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>. The second
and third method can be applied to (non-hyper)graphs rather than hypergraphs, to get a
different graph.</p>
<ul>
<li>
<p>The <em>primal graph</em> or <em>Gaifman graph</em> <span class="math">\(P(H)\)</span> of a hypergraph <span class="math">\(H\)</span> is the graph
on the vertices of <span class="math">\(H\)</span> where two vertices are connected iff they co-occur in
a hyperedge. In other words, hyperedges are encoded as cliques.
The primal graph of a (non-hyper)graph is the graph itself.</p>
</li>
<li>
<p>The <em><a href="https://en.wikipedia.org/wiki/Levi_graph">incidence graph</a></em> <span class="math">\(I(H)\)</span> of a
hypergraph <span class="math">\(H\)</span> is the bipartite graph
on the vertices and edges of <span class="math">\(H\)</span> where a vertex is connected to an edge if
the vertex occurs in that edge. In other words, hyperedges are encoded as a
vertex connected to all the vertices that it contains.</p>
<p>The incidence graph
of a (non-hyper)graph amounts to
<a href="https://en.wikipedia.org/wiki/Homeomorphism_%28graph_theory%29">subdividing</a>
each edge once.</p>
</li>
<li>
<p>The <em>line graph</em> <span class="math">\(L(H)\)</span> of a hypergraph <span class="math">\(H\)</span> is the graph on the hyperedges of
<span class="math">\(H\)</span> where two hyperedges are connected iff they share a vertex. In other
words, the vertices are encoded as cliques on the hyperedges. Alternatively,
the line graph is the primal graph of the <a href="https://en.wikipedia.org/wiki/Hypergraph">dual
hypergraph</a>.</p>
<p>This construction
also makes sense (i.e., is not the identity) for (non-hyper)graphs, where it
is also called the <em>line graph</em>.</p>
</li>
</ul>
<p>We will see in a
<a href="#graph_tractability_connections_transformations">later section</a>
how bounds on various width notions can be obtained through these
transformations (for graphs and hypergraphs).</p>
<h3><a id="graph_tractability_hypergraph_acyclicity"></a>Hypergraph acyclicity</h3>
<p>Before trying to come up with parameterized notions, there have been attempts to
formalize crisp acyclicity notions for hypergraphs. See
<a href="https://en.wikipedia.org/wiki/Hypergraph#Acyclicity">Wikipedia</a> or
<a href="http://researcher.ibm.com/researcher/files/us-fagin/jacm83b.pdf">fagin1983degrees</a>
for sources to the claims and more details. Each notion in the list is implied
by the next notion (so they are given from the least restrictive to the most
restrictive) and none of the reverse implications hold
(<a href="http://researcher.ibm.com/researcher/files/us-fagin/jacm83b.pdf">fagin1983degrees</a>,
Theorem 6.1). Further, they all collapse to the usual notion of acyclicity
(i.e., "being a forest") for hypergraphs that are actually (non-hyper)graphs
(i.e., all hyperedges have size 2).</p>
<ul>
<li>
<p><strong>α-acyclicity:</strong> we can reduce the hypergraph to the empty hypergraph with four
operations: remove an isolated vertex; remove a vertex in a single hyperedge;
remove a hyperedge contained in another; remove empty hyperedges. </p>
<p>Equivalently, a hypergraph is α-acyclic iff it has a <em>join forest</em>, which is
a forest of <em>join trees</em>, which are a
special form of tree decomposition: we require that, for each bag, there
is a hyperedge containing <em>exactly</em> the elements of the bag. There are other
equivalent characterizations of α-acyclicity which I will not define.</p>
<p>We can test in linear time whether an input hypergraph is α-acyclic, and if
so compute a join forest: see
Theorem 5.6 of <a href="http://home.mathematik.uni-freiburg.de/flum/preprints/query.ps">flum2002query</a>.
Counter-intuitively, α-acyclicity can be gained when adding hyperedges (think
of a hyperedge covering all vertices), and hence also lost when removing
vertices.</p>
</li>
<li>
<p><strong>β-acyclicity:</strong> all sub-hypergraphs of the hypergraph (including itself) are
α-acyclic; this is obviously more restrictive than α-acyclicity, in fact
strictly so, and is
testable in PTIME</p>
</li>
<li>
<p><strong>γ-acyclicity:</strong> I won't define it here; see
<a href="http://researcher.ibm.com/researcher/files/us-fagin/jacm83b.pdf">fagin1983degrees</a>.</p>
</li>
<li>
<p><strong>Berge-acyclicity</strong>: the incidence graph of the hypergraph is acyclic in the standard sense;
this is obviously testable in linear time and is strictly more restrictive than
γ-acyclicity.</p>
</li>
</ul>
<p>We now turn to acyclicity definitions with a parameter <span class="math">\(k\)</span>.
Following standard usage, we will talk of the <em>treewidth</em> of a hypergraph <span class="math">\(H\)</span>
to mean the treewidth of its primal graph <span class="math">\(P(H)\)</span>.
However, by
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, Section
5.2, there are α-acyclic hypergraphs which have unbounded treewidth, i.e., their
primal graphs have unbounded treewidth;
and ditto for the notions of incidence graphs and of line graphs.
This motivates the search for specific hypergraph definitions of treewidth (and
of the other notions presented before).</p>
<h3>Querywidth, hypertreewidth, generalized hypertreewidth</h3>
<p>A decomposition of a hypergraph,
for all three notions of width presented here,
is a tree decomposition of its primal
graph: however, the vertices of each bag are additionally covered by a set of
hyperedges, and the width of the decomposition is redefined to mean the maximal number of
<em>hyperedges</em> in a bag (where we do <em>not</em> subtract 1, unlike in the definition of
treewidth). The differences are:</p>
<ul>
<li><strong>querywidth</strong>: the hyperedges of each bag must <em>exactly</em> cover the vertices
of the bag.</li>
<li><strong>hypertreewidth</strong>: the hyperedges of each bag must cover the vertices of the
bag and they cannot include additional vertices if those occur in strict
descendants of the bag.</li>
<li><strong>generalized hypertreewidth</strong>: the hyperedges must cover the vertices, no
further restriction is imposed.</li>
</ul>
<p>Thus <span class="math">\(\text{ghtw}(H) \leq \text{tw}(P(H))\)</span> and <span class="math">\(\text{ghtw}(H) \leq \text{htw}(H)
\leq \text{qw}(H)\)</span>. In fact <span class="math">\(\text{qw}(H) \leq 1 + \text{tw}(I(G))\)</span>
(<a href="http://www.cs.ox.ac.uk/files/1030/qw.pdf">chekuri2000conjunctive</a>, Lemma 2): a tree
decomposition of the incidence graph is in particular a query decomposition when
restricting the attention to the vertices of the incidence graph that code
hyperedges, and the "+1" is because the definition of treewidth subtracts 1 to
bag sizes.</p>
<p>Further, all three notions are within a factor 3 of each other
(<a href="http://www.sciencedirect.com/science/article/pii/S0195669807000753">adler2007hypertree</a>,
<a href="http://www.cs.ox.ac.uk/people/zoltan.miklos/pods075-gottlob.pdf">gottlob2007generalized</a>),
so that "having bounded qw", "having bounded htw", and "having bounded ghtw" are
all equivalent.</p>
<p>A (non-empty) hypergraph <span class="math">\(H\)</span> is α-acyclic iff <span class="math">\(\text{ghtw}(H) = \text{htw}(H) =
\text{qw}(H) = 1\)</span> as mentioned in
<a href="https://www.mat.unical.it/~ggreco/files/GottlobGrecoScarcello.pdf">gottlob2014treewidth</a>.</p>
<p>All three notions are bounded by <span class="math">\(\lfloor n/2 \rfloor + 1\)</span> on hypergraphs with
<span class="math">\(n\)</span> vertices
(<a href="http://www.dbai.tuwien.ac.at/staff/gottlob/extcore.pdf">gottlob2005computing</a>,
Theorem 3.5 and subsequent remarks).</p>
<p>From the join tree definition, it is obvious that a hypergraph is α-acyclic iff
it has querywidth equal to 1.</p>
<p>Last, it is obvious by definition that if the arity
is bounded by a constant <span class="math">\(a\)</span>,
then we have <span class="math">\(\lfloor \text{tw}(P(H))/a \rfloor \leq \text{ghtw}(H)\)</span>. Hence,
<em>in this case</em>, "having bounded tw" is equivalent to "having bounded htw" (and
ditto for the other two hypergraph notions).</p>
<h3><a id="graph_tractability_fractional_hypertreewidth"></a> Fractional hypertreewidth</h3>
<p><span class="update">This is an addition to the original post</a></p>
<p>The notion of <em>fractional hypertreewidth</em> is defined in
grohe2014constraint (not available online) and in
<a href="http://www.cs.bme.hu/~dmarx/papers/marx-soda2009.pdf">marx2009approximating</a>.
It is again defined via tree decompositions of the primal graph of the hypergraph,
but this time we annotate them with <em>weighting</em> sets of hyperedges: for each bag <span class="math">\(b\)</span> of the tree decomposition,
we have a weighting function <span class="math">\(w_b\)</span> for bag <span class="math">\(b\)</span> that maps each hyperedge <span class="math">\(e\)</span> of the hypergraph
to a nonnegative real number <span class="math">\(w_b(e)\)</span>. We require that, for every bag <span class="math">\(b\)</span>,
the function <span class="math">\(w_b\)</span> <em>covers</em> the set <span class="math">\(S\)</span> of the vertices contained in <span class="math">\(b\)</span>, namely, for each <span class="math">\(v \in S\)</span>, the sum
<span class="math">\(w_b(e)\)</span> over all hyperedges <span class="math">\(e\)</span> of the hypergraph that contain <span class="math">\(v\)</span> must be at
least <span class="math">\(1\)</span>. The <em>width</em> of these augmented tree decompositions is the maximum,
over all bags <span class="math">\(b\)</span>, of the sum <span class="math">\(w_b(e)\)</span> over all hyperedges; and the <em>fractional
hypertree width</em> of a hypergraph is the smallest possible width of such a
decomposition.</p>
<p>Of course, the fractional hypertreewidth is less than the generalized
hypertreewidth, as generalized hypertreewidth is obtained by restricting the
decompositions to use weight functions having values in <span class="math">\(\{0, 1\}\)</span>.</p>
<h3><a id="graph_tractability_hbw"></a> Hyperbranchwidth</h3>
<p><strong>Hyperbranchwidth</strong>
(<a href="http://www.sciencedirect.com/science/article/pii/S0195669807000753">adler2007hypertree</a>)
is defined like branchwidth, with partitions of hyperedges, except that the
weight of a hyperedge partition is not its number of incident vertices, but the number of
hyperedges required to cover its incident vertices (not necessarily exactly,
i.e., we may cover a superset of them). We have
(<a href="http://www.sciencedirect.com/science/article/pii/S0195669807000753">adler2007hypertree</a>,
Lemmas 16 and 17):</p>
<ul>
<li><span class="math">\(\text{hbw}(H) \leq \text{ghw}(H)\)</span> for any hypergraph <span class="math">\(H\)</span></li>
<li><span class="math">\(\text{ghw}(H) \leq 2 \text{hbw}(H)\)</span> for any non-trivial hypergraph <span class="math">\(H\)</span> (not all
hyperedges are pairwise disjoint)</li>
</ul>
<p>Hence "bounded hyperbranchwidth" and "bounded generalized hypertreewidth" are
equivalent.</p>
<p>Apparently hyperbranchwidth is a problematic function because it is not
<a href="https://en.wikipedia.org/wiki/Submodular_set_function">submodular</a>, unlike the
functions used for branchwidth and rankwidth.</p>
<p>I do not know whether we can define variants of hyperbranchwidth with partition
weight counted as the number of hyperedges required to cover <em>exactly</em> the
vertices, and connect this to querywidth.</p>
<h3>Cliquewidth</h3>
<p>Cliquewidth is usually defined for hypergraphs as that of the <em>incidence graph</em>,
in which case we have <span class="math">\(\text{qw}(H) \leq \text{cw}(H)\)</span>, and there are
hypergraphs with bounded querywidth but unbounded cliquewidth. Hence "having
bounded querywidth" (and the other notions) is weaker than "having bounded
cliquewidth".
(<a href="http://www.researchgate.net/profile/Georg_Gottlob/publication/220616479_Hypergraphs_in_Model_Checking_Acyclicity_and_Hypertree-Width_versus_Clique-Width/links/00b49517e96d7d7f0b000000.pdf">gottlob2004hypergraphs</a>)</p>
<h3><a id="graph_tractability_connections_transformations"></a> Connections via transformations</h3>
<p>In some cases, bounds on graphs or hypergraphs relate to bounds on the incidence, line,
and primal graph.</p>
<p>The branchwidth of a (non-hyper)graph <span class="math">\(G\)</span> is the rankwidth of its incidence graph, up to
removing <span class="math">\(1\)</span>: <span class="math">\(\text{bw}(G) - 1 \leq \text{rw}(I(G)) \leq \text{bw}(G)\)</span>
(<a href="http://mathsci.kaist.ac.kr/~sangil/pdf/2006incidencerev.pdf">oum2007rank</a>).</p>
<p>The treewidth of a (non-hyper)graph can be used to bound the cliquewidth of its
line graph: <span class="math">\(.25\cdot(\text{tw}(G) + 1) \leq \text{cw}(L(G)) \leq 2 \text{tw}(G) +
2\)</span>
(<a href="http://www.sciencedirect.com/science/article/pii/S0012365X07000684">gurski2007line</a>,
Corollary 11 1., and Theorem 5).</p>
<p>The treewidth of a (non-hyper)graph is exactly that of its incidence graph:
<span class="math">\(\text{tw}(G) = \text{tw}(I(G))\)</span>
(<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, Theorem 3.22).
A similar result for cliquewidth is known assuming bounded vertex degree
(<a href="http://www.sciencedirect.com/science/article/pii/S0166218X08003351">kaminski2009recent</a>,
Proposition 8).
Further, for any hypergraph <span class="math">\(H\)</span>, we have <span class="math">\(\text{tw}(H) \leq \text{tw}(I(H)) +
1\)</span>
(<a href="http://www.mathematik.tu-darmstadt.de/~otto/papers/GHO.ps">gradel2002back</a>),
where we recall that the treewidth of a hypergraph was defined as that of its primal
graph.</p>
<p>I am not aware of results connecting width measures on hypergraph to measures
on the dual hypergraph.</p>
<h3><a id="graph_tractability_directed"></a> Directed graphs</h3>
<p>I file "directed graphs" in the same category as "hypergraphs", because it is
about having a richer incidence relation. Width definitions for directed graphs
are interesting because the usual acyclicity notion for directed graphs is
different from that of undirected graphs (i.e., "being a forest", which we
studied so far). This is an interesting area with lots of recent research that I
will not attempt to summarize here.
See <a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a> for a survey.</p>
<p>I will just note that clique decompositions can extend to directed graphs, where the operation that
creates edges is meant to create directed edges
(<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, section
4.1.1).</p>
<h2><a id="graph_tractability_complexity"></a> Complexity of recognition</h2>
<h3>Definitions</h3>
<p>Having studied all of these definitions, it is a natural question to ask, given
an (hyper)graph, how can we compute its *-width. I will only deal with the
parameterized width notions; for the crisp acyclicity definitions, I have
already given
the complexity of recognition when defining them in <a href="#graph_tractability_hypergraph_acyclicity">this
section</a>.</p>
<p>For the parameterized notions, we must be careful in the problem
definition. There are two possible tasks:</p>
<ul>
<li>Just determine the *-width of the input (hyper)graph</li>
<li>Determine the *-width <em>and</em> compute a *-decomposition of the input</li>
</ul>
<p>Further, it is often useful to study a <em>parameterized</em> version of these decision
problems. Hence, we consider two possible kinds of inputs; the first is of
course harder than the second:</p>
<ul>
<li>We are only given an input (hyper)graph and the algorithm must solve the task.</li>
<li>We have fixed <span class="math">\(k \in \mathbb{N}\)</span>; the algorithm is given a (hyper)graph with
the <a href="https://en.wikipedia.org/wiki/Promise_problem">promise</a> that its *-width is at most <span class="math">\(k\)</span>. In other words, if
its width is <span class="math">\(> k\)</span> the algorithm may do anything, otherwise it must solve the task. </li>
</ul>
<p>In the second phrasing, example situations are:</p>
<ul>
<li>the problem gets NP-hard whenever the parameter <span class="math">\(k\)</span> is given a sufficiently
large value;</li>
<li>for every <span class="math">\(k\)</span>, the problem can be solved in PTIME, i.e., for some function <span class="math">\(f : \mathbb{N} \to \mathbb{N}\)</span>, in
<span class="math">\(O(n^{f(k)})\)</span>; this is the parameterized complexity class
<a href="https://en.wikipedia.org/wiki/Parameterized_complexity#XP">XP</a> if <span class="math">\(f\)</span> is
computable (in our case it always will be);</li>
<li>the problem can be solved in complexity <span class="math">\(O(f(k) \cdot n^c)\)</span> for a fixed
(computable) function <span class="math">\(f\)</span> and a fixed constant <span class="math">\(c \in
\mathbb{N}\)</span> independent of <span class="math">\(k\)</span>, in which case we say that the problem is
<em>fixed-parameter tractable</em>
(<a href="https://en.wikipedia.org/wiki/Parameterized_complexity#FPT">FPT</a>) (and we may talk of linear-FPT, quadratic-FPT,
etc., to reflect the value <span class="math">\(c\)</span>).</li>
</ul>
<h3>Robertson-Seymour</h3>
<p>The well-known <a href="https://en.wikipedia.org/wiki/Robertson%E2%80%93Seymour_theorem">Robertson-Seymour
theorem</a> shows
that any M-closed property can be characterized by a <em>finite</em> set of <a href="https://en.wikipedia.org/wiki/Forbidden_graph_characterization">forbidden
minors</a>. As
testing whether a <em>fixed</em> graph <span class="math">\(G'\)</span> is a minor of an input graph <span class="math">\(G\)</span> can be
performed in quadratic time
(<a href="http://research.nii.ac.jp/~k_keniti/quaddp1.pdf">kawarabayashi2012disjoint</a>)<sup id="fnref:graph_tractability_minor"><a class="footnote-ref" href="#fn:graph_tractability_minor" rel="footnote">4</a></sup>;
this implies the existence<sup id="fnref:graph_tractability_existence"><a class="footnote-ref" href="#fn:graph_tractability_existence" rel="footnote">5</a></sup> of a quadratic time test for any M-closed property.
We will use this general result later.</p>
<h3>Results</h3>
<p>When <span class="math">\(k\)</span> is fixed and a graph <span class="math">\(G\)</span> is given as input:</p>
<ul>
<li>For treewidth, branchwidth, pathwidth:<ul>
<li>Determining the value of the treewidth, branchwidth, and pathwidth are
quadratic FPT
because "having treewidth <span class="math">\(\leq k\)</span>" and "having branchwidth <span class="math">\(\leq k\)</span>" are
M-closed, so we can apply the Robertson-Seymour-based reasoning above.</li>
<li>For treewidth and pathwidth, there is a linear FPT algorithm to compute the
width and a decomposition
(<a href="https://www.math.ucdavis.edu/~deloera/MISC/BIBLIOTECA/trunk/Arnborg/Arnborg5.pdf">bodlaender1996linear</a>,
the parameter being exponential in the width). The algorithm is
infeasible in practice due to huge constants. For treewidth, it is preferable in practice to use an
algorithm that computes a decomposition of a graph <span class="math">\(G\)</span> of treewidth <span class="math">\(k\)</span> in time
<span class="math">\(O(|G|^{k+2})\)</span>
(<a href="http://home.mathematik.uni-freiburg.de/flum/preprints/query.ps">flum2002query</a>, end
of Section 3), or various heuristics for approximation (see at the end of
the section).</li>
<li>Branchwidth can be computed, along with an optimal branch decomposition, in FPT linear
time (<a href="http://users.uoa.gr/~sedthilk/papers/branch.pdf">bodlaender1997constructive</a>)</li>
</ul>
</li>
<li>For rankwidth, cliquewidth:<ul>
<li>Rankwidth, and an optimal decomposition, can be computed in cubic FPT time
(<a href="http://www.fi.muni.cz/~hlineny/papers/partition.pdf">hlineny2007finding</a>).</li>
<li>It is PTIME to determine the cliquewidth for <span class="math">\(k \leq 3\)</span>
(corneil2012polynomial, requires a subscription); otherwise this is still
<a href="/work/research/questions/#computing-cliquewidth">open</a>.</li>
</ul>
</li>
</ul>
<p>For hypergraph acyclicity measures (α-acylicity, etc.), refer back to <a href="#graph_tractability_hypergraph_acyclicity">the
paragraph</a> where they are defined.</p>
<p>For hypergraph measures, when <span class="math">\(k\)</span> is fixed and a hypergraph <span class="math">\(H\)</span> is given as input:</p>
<ul>
<li>It is NP-complete to decide whether an input hypergraph <span class="math">\(H\)</span> has generalized
hypertreewidth 3
(<a href="http://www.dbai.tuwien.ac.at/staff/miklos/ghw.pdf">gottlob2007generalized</a>).
For 2, I <a href="https://cstheory.stackexchange.com/questions/35942/complexity-of-testing-if-a-hypergraph-has-generalized-hypertreewidth-2">do not
know</a> the complexity.</li>
<li>It is NP-complete to decide whether an input hypergraph <span class="math">\(H\)</span> has querywidth 4
(<a href="http://www.sciencedirect.com/science/article/pii/S0022000001918094">gottlob2002hypertree</a>).</li>
<li>For any <span class="math">\(k\)</span>, we can determine in PTIME whether an input hypergraph <span class="math">\(H\)</span> has
hypertreewidth <span class="math">\(\leq k\)</span>, and if so compute a decomposition
(<a href="http://www.sciencedirect.com/science/article/pii/S0022000001918094">gottlob2002hypertree</a>);
however this is
unlikely to be in FPT
(<a href="http://www.automata.rwth-aachen.de/~grohe/pub/ggmss05.pdf">gottlob2005hypertree</a>).</li>
<li>We can test in linear time whether it has generalized hypertreewidth 1,
querywidth 1, or hypertreewidth 1, because this is equivalent to it being
α-acyclic (mentioned in <a href="https://www.mat.unical.it/~ggreco/files/GottlobGrecoScarcello.pdf">gottlob2014treewidth</a>).</li>
</ul>
<p>When a graph <span class="math">\(G\)</span> is given as input, with no bound on the parameter <span class="math">\(k\)</span>:</p>
<ul>
<li>Treewidth is NP-hard to compute on general graphs; it is computable in PTIME
on <a href="https://en.wikipedia.org/wiki/Chordal_graph">chordal graphs</a>
(<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.107.2561&rep=rep1&type=pdf">bodlaender2007combinatorial</a>,
after Lemma 11); on planar graphs,
this is
<a href="https://cstheory.stackexchange.com/questions/32505/is-it-still-open-to-determine-the-complexity-of-computing-the-treewidth-of-plana">open</a>.</li>
<li>Branchwidth is NP-hard on general graphs, but on planar graphs it can be
determined and a decomposition constructed in PTIME
(<a href="http://people.math.gatech.edu/~thomas/PAP/ratcatch.pdf">seymour1994call</a>;
cubic bound shown in gu2005optimal, unavailable without subscriptions).</li>
<li>Cliquewidth is NP-hard to compute
(<a href="http://www.kr.tuwien.ac.at/drm/szeider/papers/sidmafinal.pdf">fellows2009clique</a>).</li>
<li><span class="update">Fractional hypertreewidth can be approximated in PTIME: given a hypergraph
<span class="math">\(H\)</span>, we can compute in PTIME a fractional hypertree decomposition of width
<span class="math">\(O(w^3)\)</span> of <span class="math">\(H\)</span>, where <span class="math">\(w\)</span> is the real fractional hypertreewidth: see
<a href="http://www.cs.bme.hu/~dmarx/papers/marx-soda2009.pdf">marx2009approximating</a>.</span></li>
</ul>
<p>There are <a href="http://cstheory.stackexchange.com/a/6035">practical implementations</a>
to compute tree decompositions of graphs, trying to compute the optimal treewidth or an approximation
thereof. A fellow student of mine successfully used
<a href="http://www.treewidth.com/">libtw</a>.
See Section 4.2 of
<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.107.2561&rep=rep1&type=pdf">bodlaender2007combinatorial</a>
for more details about how treewidth can be <em>approximated</em> (including, e.g., the
use of
<a href="https://en.wikipedia.org/wiki/Metaheuristic">metaheuristics</a>).
See also <a href="http://www.sciencedirect.com/science/article/pii/S0890540109000947">bodlaender2009treewidth</a>.</p>
<h2><a id="graph_tractability_logical"></a> Logical problems</h2>
<h3>Logics</h3>
<p><em><a href="https://en.wikipedia.org/wiki/Propositional_calculus">Propositional logic</a></em>
(Boolean connectives) is the logic allowing variables and
<a href="https://en.wikipedia.org/wiki/Logical_connective">Boolean connectives</a>:
negation, conjunction, disjunction. Propositional logic formulae are often given
in <a href="https://en.wikipedia.org/wiki/Conjunctive_normal_form">conjunctive normal
form</a> (CNF), i.e., a
conjunction of clauses which are disjunctions of literals (variables or negated
variables); or in
<a href="https://en.wikipedia.org/wiki/Disjunctive_normal_form">disjunctive normal
form</a> (a disjunction of
conjunctions of literals).</p>
<p>(Function-free) <em><a href="https://en.wikipedia.org/wiki/First-order_logic">first-order logic</a></em>
(FO)
is the
logic obtained from propositional logic by allowing
<a href="https://en.wikipedia.org/wiki/Existential_quantification">existential</a>
and <a href="https://en.wikipedia.org/wiki/Universal_quantification">universal</a>
quantifiers.</p>
<p><em><a href="https://en.wikipedia.org/wiki/Monadic_second-order">Monadic second-order logic</a></em>
(MSO) is the logic obtained from FO by further allowing existential and
universal quantification over sets (unary relations).</p>
<p><em>Monadic second-order logic with edge quantification</em>
(MSO2) is the logic on graphs that further allows quantification over sets of
edges. Its generalization to hypergraphs (quantifying over relations of
arbitrary arity) is called
<em>guarded second-order logic</em> (GSO). In GSO, quantifications
over relations of arity <span class="math">\(>1\)</span> are semantically restricted to always range over <em>guarded</em> tuples,
i.e., tuples of values that already co-occur in a hyperedge. Likewise,
quantification over sets of edges in MSO2 means quantifications over edges in
the actual structure, not quantification over arbitrary pairs. However, this
should <em>not</em> be confused with
<a href="https://en.wikipedia.org/wiki/Guarded_logic">guarded logics</a>, where
<em>first-order</em> quantification is restricted as well: MSO2 and GSO without
second-order quantification is exactly FO, it is not restricted to the guarded
fragment of FO.</p>
<p>It turns out that MSO2 over graphs is equivalent to MSO over the
<em>incidence graph</em> of these graphs, where the incidence graph is assumed to be
labeled in a way that allows the logic to distinguish between vertices and
edges. More generally, GSO over hypergraphs (or labeled hypergraphs, i.e.,
relational signatures) is equivalent to MSO on the incidence instance
(<a href="http://www.mathematik.tu-darmstadt.de/~otto/papers/GHO.ps">gradel2002back</a>,
Proposition 7.1).</p>
<p>An example of a proposition that can be expressed in MSO2 but not MSO is the
existence of a
<a href="https://en.wikipedia.org/wiki/Hamiltonian_path">Hamiltonian cycle</a> in a graph
(see <a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, Section 3.2).</p>
<h3>Problems</h3>
<p>The
<em><a href="https://en.wikipedia.org/wiki/Satisfiability">satisfiability problem</a></em> for a
logic <span class="math">\(\mathcal{L}\)</span> and class of (hyper)graphs <span class="math">\(\mathcal{C}\)</span> asks,
given a formula <span class="math">\(\phi \in \mathcal{L}\)</span>, whether it has a model in <span class="math">\(\mathcal{C}\)</span>.</p>
<p>The satisfiability problem for MSO2 sentences, MSO sentences, and actually FO
sentences is undecidable over
general graphs (even over finite graphs, in fact; see
<a href="https://en.wikipedia.org/wiki/Trakhtenbrot's_theorem">Trakhtenbrot's theorem</a>
which is the corresponding result for
<a href="https://en.wikipedia.org/wiki/Validity">validity</a>, i.e., the negation of
satisfiability of the negated formula).
For propositional logic, the problem
<a href="https://en.wikipedia.org/wiki/Boolean_satisfiability_problem">SAT</a>
of deciding whether a
propositional formula is satisfiable is NP-complete.</p>
<p>The
<em><a href="https://en.wikipedia.org/wiki/Model_checking">model-checking problem</a></em> for a
logic <span class="math">\(\mathcal{L}\)</span> and class of (hyper)graphs <span class="math">\(\mathcal{C}\)</span>, asks
for a <em>fixed</em> formula <span class="math">\(\phi \in \mathcal{L}\)</span> with no free variables, given an
input (hyper)graph <span class="math">\(G \in \mathcal{C}\)</span>, whether <span class="math">\(G\)</span>
satisfies <span class="math">\(\phi\)</span> in the logical sense.
I will not study the version of model checking where both the formula and
(hyper)graph are given as input, which is of course considerably harder.</p>
<p>The model-checking problem for MSO in general is hard for every level of the
polynomial hierarchy
(<a href="http://www.sciencedirect.com/science/article/pii/S0022000099916914">ajtai2000closure</a>).
A simple example that shows NP-hardness on graphs is asking whether an input
graph can be <a href="https://en.wikipedia.org/wiki/Graph_coloring">colored</a> with 3
colors, which is MSO-expressible.</p>
<p>A variant of the model-checking problem is the <em>counting problem</em> that asks,
for a formula with free variables, given a (hyper)graph, how many assignments of
the free variables satisfy the formula; and the <em>enumeration problem</em>, that
requests that the satisfying assignments be computed (with complexity measured
<a href="https://en.wikipedia.org/wiki/Output-sensitive_algorithm">as a function of the size of the
output</a>, or measured
as the maximum delay between two enumerated outputs).</p>
<h3>Monadic second order</h3>
<p>For satisfiability, it is known that, for any <span class="math">\(k\)</span>, satisfiability for MSO2 over the class of
graphs of treewidth <span class="math">\(\leq k\)</span> is decidable
(<a href="http://www.sciencedirect.com/science/article/pii/016800729190054P">seese1991structure</a>);
this implies the same for branchwidth (an equivalent claim) and pathwidth (a
weaker claim). Conversely, it is known that for any class of graphs of unbounded
treewidth, satisfiability for MSO2 is undecidable: this relies on a different
result by Robertson and Seymour, the
<a href="https://en.wikipedia.org/wiki/Grid_minor_theorem">grid minor theorem</a>, to
extract large grid minors from unbounded treewidth graphs, and using the fact
that the MSO theory of grids is undecidable. For details see
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, Section 6.</p>
<p>Further, it is known that, for any <span class="math">\(k\)</span>, satisfiability for MSO over the class of
graph of cliquewidth <span class="math">\(\leq k\)</span> is decidable. The converse result was conjectured
in
<a href="http://www.sciencedirect.com/science/article/pii/016800729190054P">seese1991structure</a>
and a weakening was proven in
<a href="http://www.sciencedirect.com/science/article/pii/S0095895606000463">courcelle2007vertex</a>:
it shows the converse result but for a logic further allowing to test that a set
variable of MSO is interpreted by a set of even cardinality. Also, it is already
known that a class of graphs has bounded cliquewidth iff it is interpretable in
the class of colored trees (cited as Lemma 4.22 in
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>).</p>
<p>For model checking, it is known that the problem for MSO2 on bounded treewidth
structures is FPT linear (with the formula and the width bound as parameter),
see
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, Section 3.4; this is
what is known as <a href="https://en.wikipedia.org/wiki/Courcelle's_theorem">Courcelle's
theorem</a>.
The
model checking problem for MSO on bounded cliquewidth structures is FPT cubic,
the bottleneck being the computation of the rank decomposition:
see <a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, Section 4.3; this
is also due to Courcelle.
The FPT tractability (not linearity) of MSO2 on bounded treewidth reduces to the
same result for MSO and bounded cliquewidth by going through the incidence graph
(see <a href="http://www.labri.fr/perso/courcell/Conferences/ExpoCIRM2015.pdf">these
slides</a>, slide 8).</p>
<p>The tractability of MSO on bounded cliquewidth does not extend to MSO2. Indeed,
some problems definable in MSO2 but not in MSO are known to be W[1]-hard when
parameterized by clique-width, e.g., Hamiltonian cycle, see
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.144.1443">fomin2009clique</a>
and
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.154.5929">fomin2010algorithmic</a>.
Further, it is known that there is a MSO2 formula such that model checking on
the class of all unlabeled cliques (which has bounded cliquewidth) is not in
PTIME, assuming <span class="math">\(\text{P}_1 \neq \text{NP}_1\)</span> (those are <a href="https://en.wikipedia.org/wiki/Unary_language#Tally_classes">unary
languages</a>):
see Theorem 6 of
<a href="http://perso.ens-lyon.fr/eric.thierry/Graphes2007/cmr00.pdf">courcelle2000linear</a>.</p>
<p>For model-checking, the constant factor that depends on the fixed formula <span class="math">\(\phi\)</span> is
<a href="https://en.wikipedia.org/wiki/Nonelementary_problem">nonelementary</a> even for
a formula in FO
(<a href="http://www.sciencedirect.com/science/article/pii/S0168007204000612">frick2004complexity</a>).</p>
<p>The tractability results for model checking on bounded treewidth structures are
usually shown using <em>interpretability</em> results to translate the logic on the
instances to a logic on the (suitably annotated) tree decompositions (see
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>),
and using a connection from MSO on trees to
<a href="https://en.wikipedia.org/wiki/Tree_automaton">tree automata</a> that originated in
thatcher1968generalized (subscription required). See
<a href="http://home.mathematik.uni-freiburg.de/flum/preprints/query.ps">flum2002query</a> for a
summary.
A connection to automata for bounded rankwidth structures was more recently
investigated in
<a href="http://www.sciencedirect.com/science/article/pii/S0166218X09004211">ganian2010parse</a>.</p>
<p>The necessity of bounded treewidth for the tractability of model-checking under
<em>closure assumptions</em> (i.e., S-closed, M-closed, etc.) was studied in
<a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a>.
The S-closed case was
refined in
<a href="http://arxiv.org/abs/1001.5019">kreutzer2011lower</a> (for MSO2), and in
<a href="http://arxiv.org/abs/1109.5804">ganian2012lower</a> (for MSO but additionally assuming closure
under vertex labellings).</p>
<p>The problem of counting the number of assignments to a MSO formula is also known
to be linear on bounded treewidth (hyper)graphs
(<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.12.2544&rep=rep1&type=pdf">arnborg1991easy</a>),
and computing the assignments (the enumeration problem) can be
done in time linear in the input and in the output
(<a href="http://home.mathematik.uni-freiburg.de/flum/preprints/query.ps">flum2002query</a>).
For results on constant-delay enumeration, see, e.g.,
<a href="http://www.lsv.ens-cachan.fr/~segoufin/Papers/Mypapers/cdlin-survey.pdf">segoufin2012enumerating</a>.</p>
<h3><a id="graph_tractability_fo"></a> First-order</h3>
<p>I am not aware of conditions that try to ensure decidability of FO
satisfiability (in the spirit of those for MSO and MSO2 above), so I focus on model checking.</p>
<p>The model-checking problem for FO is in PTIME, in fact in
<a href="https://en.wikipedia.org/wiki/AC0">AC<sup>0</sup></a>, but this does <em>not</em> imply
that it is FPT (where the query is the parameter): the degree of the polynomial
in the (hyper)graph depends in general on the formula.</p>
<p>It is more complicated for FO than for MSO to find criteria that
guarantee that FO model checking is FPT, because of locality properties of FO. In
particular, there are notions of locally tree-decomposable structures
(<a href="http://arxiv.org/abs/cs/0004007">frick2001deciding</a>), which ensure FPT
linearity of FO model checking in more general situations.</p>
<p>For more about FO, see Section 7 of
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, noting that Open
Problem 7.23 has now been solved in the affirmative
(<a href="http://arxiv.org/abs/1109.5036">dvorak2013testing</a>).</p>
<p>The problem of enumeration for first-order is also studied in
<a href="http://www.lsv.ens-cachan.fr/~segoufin/Papers/Mypapers/cdlin-survey.pdf">segoufin2012enumerating</a>.</p>
<h3>Propositional logic</h3>
<p>The model-checking problem for propositional formulae is obviously always
tractable.
However, it is more interesting, given a propositional formula in normal form,
encoded as an instance, to determine whether it is satisfiable
(<a href="https://en.wikipedia.org/wiki/Boolean_satisfiability_problem">SAT</a>), and count the
number of satisfying assignments (<a href="https://en.wikipedia.org/wiki/Sharp-SAT">#SAT</a>).</p>
<p>The standard way to represent a
<a href="https://en.wikipedia.org/wiki/Conjunctive_normal_form">conjunctive normal form</a>
formula is as a bipartite graph between clauses and variables with colored edges
indicating whether a variable occurs positively or negatively in a clause
(see <a href="http://arxiv.org/abs/1006.5621">ganian2010better</a>, Definition 2.7).
It is then known that SAT and #SAT are FPT if this graph has bounded treewidth
or if it has bounded rankwidth (see
<a href="http://arxiv.org/abs/1006.5621">ganian2010better</a> and references therein).</p>
<p>Tractability for #SAT is known for other cases, e.g., when the
standard representation of the formula as a hypergraph is β-acyclic
(<a href="http://arxiv.org/abs/1405.6043">brault2014understanding</a>).</p>
<h2><a id="graph_tractability_csp"></a> Query evaluation and constraint satisfaction problems</h2>
<h3>Problems</h3>
<p>This section studies the <a href="https://en.wikipedia.org/wiki/Constraint_satisfaction_problem">constraint satisfaction
problem</a>,
formalized as the problem <em>CSP</em> of deciding, given two relational instances <span class="math">\(I_1\)</span> and
<span class="math">\(I_2\)</span>,
whether there is a homomorphism from <span class="math">\(I_1\)</span> to <span class="math">\(I_2\)</span>, i.e., an application
mapping the elements of <span class="math">\(I_1\)</span> to those of <span class="math">\(I_2\)</span> such that each fact (hyperedge)
of <span class="math">\(I_1\)</span> exists in <span class="math">\(I_2\)</span> when mapped by the homomorphism; as well as a
<em>counting variant</em> that asks <em>how many</em> such homomorphisms exist.</p>
<p>The CSP problem is also studied in
<a href="https://en.wikipedia.org/wiki/Database_theory">database theory</a>,
seen as Boolean
<a href="https://en.wikipedia.org/wiki/Conjunctive_query">conjunctive query</a> (CQ)
evaluation: a
Boolean CQ is an FO sentence consisting of an existentially quantified
conjunction of atoms. It is clear that a CQ <span class="math">\(Q\)</span> is satisfied in an instance <span class="math">\(I\)</span> iff there
is a homomorphism from <span class="math">\(I_Q\)</span> to <span class="math">\(I\)</span> where <span class="math">\(I_Q\)</span> is the <em>canonical instance</em>
associated to <span class="math">\(Q\)</span>.</p>
<p>One problem phrasing is when both <span class="math">\(I_1\)</span> and <span class="math">\(I_2\)</span> are given as input, which I
will call the <em>combined complexity</em> approach. In this case, it is sensible to
restrict <span class="math">\(I_1\)</span> and <span class="math">\(I_2\)</span> to live in fixed (generally infinite) classes <span class="math">\(C_1\)</span> and <span class="math">\(C_2\)</span>,
and study how the choice of class influences the complexity.</p>
<p>Another problem phrasing, common in database theory, is when one of <span class="math">\(C_1\)</span> and
<span class="math">\(C_2\)</span> is a singleton class, so we are in one of two settings:</p>
<ul>
<li><strong>data complexity:</strong> <span class="math">\(I_1\)</span> is a fixed structure and <span class="math">\(I_2\)</span> is the input</li>
<li><strong>query complexity:</strong> <span class="math">\(I_2\)</span> is a fixed structure and <span class="math">\(I_1\)</span> is the input</li>
</ul>
<p>The question then becomes how the complexity of the CSP problem evolves depending on
the fixed structure, and on the class in which the input structures may be
taken; so this is really the combined complexity approach but with one of the
classes being a singleton (so the corresponding structure is effectively fixed
rather than given as input).</p>
<h3><a id="graph_tractability_csp_results"></a> Results</h3>
<p>Without any restriction, the CSP problem is clearly in NP in combined complexity
(guess the homomorphism and check it) and its counting variant is in #P (count
nondeterministically over all mappings that are checked to be homomorphisms).
The CSP problem is easily seen to be NP-hard in
query complexity for very simple <span class="math">\(I_2\)</span>, even when <span class="math">\(C_1\)</span> is the class of graphs:
fixing <span class="math">\(I_2\)</span> to be a triangle,
an input <span class="math">\(I_1\)</span> has a homomorphism to <span class="math">\(I_2\)</span> iff it is
<a href="https://en.wikipedia.org/wiki/Graph_coloring">3-colorable</a>. For any fixed
<span class="math">\(I_1\)</span>, the data
complexity of the CSP problem when <span class="math">\(C_2\)</span> is all structures is in
<a href="https://en.wikipedia.org/wiki/AC0">AC<sup>0</sup></a> from FO model checking, but
it is
<a href="https://en.wikipedia.org/wiki/Parameterized_complexity#W.5B1.5D">W[1]-complete</a>
(<a href="http://www.sciencedirect.com/science/article/pii/S0022000099916264">papadimitriou1999complexity</a>, Theorem 1)
and hence unlikely to be in FPT.</p>
<p>For arbitrary <span class="math">\(I_1\)</span>, data complexity becomes FPT when the input instances <span class="math">\(I_2\)</span>
are restricted to have bounded treewidth or bounded cliquewidth, from the
<a href="#graph_tractability_fo">results on FO</a>.</p>
<p>Combined complexity becomes
<a href="https://en.wikipedia.org/wiki/LOGCFL">LOGCFL</a>-complete (and hence in PTIME) when
<span class="math">\(C_2\)</span> is a class of bounded querywidth structures, or structures of
bounded degree of cyclicity (yet another definition),
and they are given with a suitable decomposition
(<a href="http://www.dbai.tuwien.ac.at/staff/gottlob/acyclic.ps">gottlob2001complexity</a>).
This generalizes an earlier analogous result for α-acyclic queries
(yannakakis1981algorithms, seems unavailable online).
For bounded treewidth or bounded hypertreewidth,
the same result holds but the decomposition can even be computed in LOGCFL, so
it doesn't need to be given.
<span class="update">The PTIME membership still holds when <span class="math">\(C_2\)</span> is a class of bounded fractional
hypertreewidth structures (grohe2014constraint, unavailable online).</span></p>
<p>For hypergraphs of fixed arity, assuming that <span class="math">\(\text{FPT} \neq W[1]\)</span>, it is
known that the combined complexity where <span class="math">\(C_2\)</span> is all structures is in PTIME iff
<span class="math">\(C_1\)</span> has bounded treewidth modulo homomorphic equivalence. This result
generalizes to the problem of <em>counting</em> the number of homomorphisms
(<a href="http://www.sciencedirect.com/science/article/pii/S0304397504005560">dalmau2004counting</a>).
In cases where <span class="math">\(C_1\)</span> satisfies this condition, the CSP problem is FPT with the
parameter being the size of <span class="math">\(I_1\)</span>. A trichotomy result for the complexity in
such cases is given in <a href="http://arxiv.org/abs/1306.5424">chen2013fine</a>, including
for counting.</p>
<p>When restricting <span class="math">\(C_1\)</span> and <span class="math">\(C_2\)</span> to
graphs (not hypergraphs), an analogous result is known for combined complexity
when <span class="math">\(C_1\)</span> is all structures:
tractability holds iff <span class="math">\(C_2\)</span> is bipartite
(<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9013&rep=rep1&type=pdf">grohe2007complexity</a>),
otherwise NP-completeness holds. The Feder-Vardi conjecture claims that there is
an analogous
dichotomy even when <span class="math">\(C_1\)</span> and <span class="math">\(C_2\)</span> can be hypergraphs rather than graphs (i.e., the query complexity
of CSP is never, e.g., in
<a href="https://en.wikipedia.org/wiki/NP-intermediate">NPI</a>). This fundamental problem is still
<a href="/work/research/questions/#feder-vardi-conjecture">open</a>.</p>
<h2><a id="graph_tractability_posets"></a> Partial order theory</h2>
<p>As bonus material, because I love
<a href="https://en.wikipedia.org/wiki/Partially_ordered_set">partial order</a> (poset) theory:
an unconvential way to look for tractability parameters on graphs is to look at
tractability parameters on posets and look at the (directed) graphs defined by
the <a href="https://en.wikipedia.org/wiki/Transitive_reduction">transitive reduction</a>
of these posets, namely, their
<a href="https://en.wikipedia.org/wiki/Hasse_diagram">Hasse diagrams</a>; and look at the
<em>cover graph</em> which is the undirected version of the Hasse diagram.</p>
<p>There has been recent work connecting the tractability measure of
<a href="https://en.wikipedia.org/wiki/Order_dimension">order dimension</a> on posets to
graph measures on the cover graph. Here are results, for any poset <span class="math">\(P\)</span> with
cover graph <span class="math">\(G\)</span>:</p>
<ul>
<li>If <span class="math">\(\text{tw}(G) \leq 2\)</span> then <span class="math">\(\text{dim}(P) \leq 1276\)</span>
(<a href="http://arxiv.org/abs/1406.3397">joret2015dimension</a>)</li>
<li>There are posets with <span class="math">\(\text{tw}(G) = 3\)</span> but <span class="math">\(\text{dim}(P)\)</span> is unbounded
(<a href="http://arxiv.org/abs/1406.3397">joret2015dimension</a>)</li>
<li>If <span class="math">\(G\)</span> is planar and the
<a href="https://en.wikipedia.org/wiki/Antichain#Height_and_width">height</a> of <span class="math">\(P\)</span> is
bounded then <span class="math">\(\text{dim}(P)\)</span> is bounded
(cited in <a href="http://arxiv.org/abs/1406.3397">joret2015dimension</a>)</li>
<li>If both <span class="math">\(\text{tw}(G)\)</span> and the height of <span class="math">\(P\)</span> are bounded then so is <span class="math">\(\text{dim}(P)\)</span>
(<a href="http://arxiv.org/abs/1301.5271">joret2015tree</a>)</li>
</ul>
<p>Last, a note about something that confused me: imposing that a poset is
<a href="https://en.wikipedia.org/wiki/Series-parallel_partial_order">series-parallel</a>
is <em>not</em> the same as imposing that its cover graph is a
<a href="https://en.wikipedia.org/wiki/Series-parallel_graph">series-parallel graph</a>.
The N-shaped poset, which is the standard example of a non-series-parallel
poset, but its cover graph is just a
<a href="https://en.wikipedia.org/wiki/Path_graph">path graph</a>. Hence series-parallel
posets intrinsically rely on directionality.</p>
<h2><a id="graph_tractability_doi"></a> List of DOIs</h2>
<p>To ensure that the references in this article can still be followed even if some
preprints are removed from the Web, here is the DOI of the citations, in
the order in which they appear in the text.</p>
<ul>
<li><a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>:
10.1093/comjnl/bxm052</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0304397597002284">bodlaender1998partial</a>:
10.1016/S0304-3975(97)00228-4</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/009589569190061N">robertson1991graph10</a>:
10.1016/0095-8956(91)90061-N</li>
<li><a href="http://mathsci.kaist.ac.kr/~sangil/pdf/2006incidencerev.pdf">oum2007rank</a>:
10.1002/jgt.20280</li>
<li><a href="http://mathsci.kaist.ac.kr/~sangil/pdf/vertexminor-revision.pdf">oum2005rank</a>:
10.1016/j.jctb.2005.03.003</li>
<li><a href="http://www.researchgate.net/publication/220181029_On_the_Clique-Width_of_Some_Perfect_Graph_Classes">golumbic2000clique</a>:
10.1142/S0129054100000260</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0095895605001528">oum2006approximating</a>:
10.1016/j.jctb.2005.10.006</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0166218X08003351">kaminski2009recent</a>:
10.1016/j.dam.2008.08.022</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a>:
10.1016/S0304-3975(02)00449-8</li>
<li><a href="http://www.labri.fr/perso/courcell/CoursMaster/BC-Olariu(2000).pdf">courcelle1990upper</a>:
10.1016/S0166-218X(99)00184-5</li>
<li>courcelle1995logical: I couldn't locate the article or a DOI. Full reference
from <a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a>: B. Courcelle, J. Engelfriet, <em>A logical
characterization of the sets of hypergraphs defined by hyperedge
replacement grammars</em>, Math. Systems Theory 28 (1995) 515–552.</li>
<li><a href="http://researcher.ibm.com/researcher/files/us-fagin/jacm83b.pdf">fagin1983degrees</a>: 10.1145/2402.322390</li>
<li><a href="http://www.cs.ox.ac.uk/files/1030/qw.pdf">chekuri2000conjunctive</a>:
10.1016/S0304-3975(99)00220-0</li>
<li><a href="http://www.tdi.informatik.uni-frankfurt.de/~adler/publications/eurocomb05.pdf">adler2006hypertree</a>:
10.1016/j.ejc.2007.04.013</li>
<li><a href="http://www.cs.ox.ac.uk/people/zoltan.miklos/pods075-gottlob.pdf">gottlob2007generalized</a>:
10.1145/1265530.1265533</li>
<li><a href="https://www.mat.unical.it/~ggreco/files/GottlobGrecoScarcello.pdf">gottlob2014treewidth</a>:
in a book with ISBN 978-1107025196</li>
<li><a href="http://www.dbai.tuwien.ac.at/staff/gottlob/extcore.pdf">gottlob2005computing</a>:
10.1145/1065167.1065187</li>
<li>grohe2014constraint: not available online, DOI 10.1145/2636918</li>
<li><a href="http://www.cs.bme.hu/~dmarx/papers/marx-soda2009.pdf">marx2009approximating</a>:
Full reference: D. Marx, <em>Approximating fractional hypertree width</em>, SODA<ol>
<li>DOI of proceedings: 10.1137/1.9781611973068</li>
</ol>
</li>
<li><a href="http://www.researchgate.net/profile/Georg_Gottlob/publication/220616479_Hypergraphs_in_Model_Checking_Acyclicity_and_Hypertree-Width_versus_Clique-Width/links/00b49517e96d7d7f0b000000.pdf">gottlob2004hypergraphs</a>: 10.1137/S0097539701396807</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0012365X07000684">gurski2007line</a>:
10.1016/j.disc.2007.01.020</li>
<li><a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>: arXiv:0902.3616
(not a DOI)</li>
<li><a href="http://www.mathematik.tu-darmstadt.de/~otto/papers/GHO.ps">gradel2002back</a>:
10.1145/507382.507388</li>
<li><a href="http://research.nii.ac.jp/~k_keniti/quaddp1.pdf">kawarabayashi2012disjoint</a>:
10.1016/j.jctb.2011.07.004</li>
<li><a href="https://www.math.ucdavis.edu/~deloera/MISC/BIBLIOTECA/trunk/Arnborg/Arnborg5.pdf">bodlaender1996linear</a>:
10.1145/167088.167161</li>
<li><a href="http://home.mathematik.uni-freiburg.de/flum/preprints/query.ps">flum2002query</a>:
10.1145/602220.602222</li>
<li><a href="http://users.uoa.gr/~sedthilk/papers/branch.pdf">bodlaender1997constructive</a>:
10.1007/3-540-63165-8_217</li>
<li><a href="http://www.fi.muni.cz/~hlineny/papers/partition.pdf">hlineny2007finding</a>:
10.1137/070685920</li>
<li>corneil2012polynomial: 10.1016/j.dam.2011.03.020</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0022000001918094">gottlob2002hypertree</a>:
10.1006/jcss.2001.1809</li>
<li><a href="http://www.automata.rwth-aachen.de/~grohe/pub/ggmss05.pdf">gottlob2005hypertree</a>:
10.1007/11604686_1</li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.107.2561&rep=rep1&type=pdf">bodlaender2007combinatorial</a>:
10.1093/comjnl/bxm037</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0890540109000947">bodlaender2009treewidth</a>:
10.1016/j.ic.2009.03.008</li>
<li><a href="http://people.math.gatech.edu/~thomas/PAP/ratcatch.pdf">seymour1994call</a>:
10.1007/BF01215352</li>
<li>gu2005optimal: 10.1145/1367064.1367070</li>
<li><a href="http://www.kr.tuwien.ac.at/drm/szeider/papers/sidmafinal.pdf">fellows2009clique</a>:
10.1137/070687256</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0022000099916914">ajtai2000closure</a>:
10.1006/jcss.1999.1691</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/016800729190054P">seese1991structure</a>:
10.1016/0168-0072(91)90054-P</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0095895606000463">courcelle2007vertex</a>:
10.1016/j.jctb.2006.04.003</li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.144.1443">fomin2009clique</a>:
No DOI. Full reference: F. V. Fomin, P. A. Golovach, D. Lokshtanov, S.
Saurabh, <em>Clique-width: on the price of generality</em>, 2009. DOI of
proceedings: 10.1137/1.9781611973068.</li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.154.5929">fomin2010algorithmic</a>:
10.1137/1.9781611973075.42</li>
<li><a href="http://perso.ens-lyon.fr/eric.thierry/Graphes2007/cmr00.pdf">courcelle2000linear</a>:
10.1007/s002249910009</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0168007204000612">frick2004complexity</a>:
10.1016/j.apal.2004.01.007</li>
<li>thatcher1968generalized: 10.1007/BF01691346</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0166218X09004211">ganian2010parse</a>:
10.1016/j.dam.2009.10.018</li>
<li><a href="http://arxiv.org/abs/1001.5019">kreutzer2011lower</a>: arXiv:1001.5019 (not a
DOI)</li>
<li><a href="http://arxiv.org/abs/1109.5804">ganian2012lower</a>: arXiv:1109.5804 (not a
DOI)</li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.12.2544&rep=rep1&type=pdf">arnborg1991easy</a>:
10.1016/0196-6774(91)90006-K</li>
<li><a href="http://www.lsv.ens-cachan.fr/~segoufin/Papers/Mypapers/cdlin-survey.pdf">segoufin2012enumerating</a>:
10.1145/2448496.2448498</li>
<li><a href="http://arxiv.org/abs/cs/0004007">frick2001deciding</a>: arXiv:cs/0004007 (not
a DOI)</li>
<li><a href="http://arxiv.org/abs/1109.5036">dvorak2013testing</a>: arXiv:1109.5036 (not a
DOI)</li>
<li><a href="http://arxiv.org/abs/1006.5621">ganian2010better</a>: arXiv:1006.5621 (not a
DOI)</li>
<li><a href="http://arxiv.org/abs/1405.6043">brault2014understanding</a>: arXiv:1405.6043
(not a DOI)</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0022000099916264">papadimitriou1999complexity</a>:
10.1006/jcss.1999.1626</li>
<li><a href="http://www.dbai.tuwien.ac.at/staff/gottlob/acyclic.ps">gottlob2001complexity</a>:
10.1145/382780.382783</li>
<li>yannakakis1981algorithms: I couldn't locate the article or a DOI. Full
reference from
<a href="http://www.dbai.tuwien.ac.at/staff/gottlob/acyclic.ps">gottlob2001complexity</a>: M.
Yannakakis, <em>Algorithms for acyclic database schemes</em>, Proc. VLDB, 1981. In
C. Zaniolo and C. Delobel, eds, pages 82-94.</li>
<li><a href="http://www.sciencedirect.com/science/article/pii/S0304397504005560">dalmau2004counting</a>:
10.1016/j.tcs.2004.08.008</li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9013&rep=rep1&type=pdf">grohe2007complexity</a>:
10.1145/1206035.1206036</li>
<li><a href="http://arxiv.org/abs/1406.3397">joret2015dimension</a>: arXiv:1406.3397 (not a
DOI)</li>
<li><a href="http://arxiv.org/abs/1301.5271">joret2015tree</a>: arXiv:1301.5271 (not a DOI)</li>
<li>corneil2005relationship: 10.1137/S0097539701385351</li>
</ul>
<div class="footnote">
<hr />
<ol>
<li id="fn:graph_tractability_bw2">
<p>However, in point (iii) in the list of
<a href="http://www.fi.muni.cz/~hlineny/papers/Wmain.pdf">hlineny2007width</a>, the
definition of "series-parallel graph" can be misleading. I would
rephrase point (iii) as: <span class="math">\(G\)</span> has bw <span class="math">\(\leq 2\)</span> iff <span class="math">\(G\)</span> does not contain
<a href="https://en.wikipedia.org/wiki/Complete_graph"><span class="math">\(K_4\)</span></a> as a
<a href="https://en.wikipedia.org/wiki/Graph_minor">minor</a> (<a href="http://www.sciencedirect.com/science/article/pii/S0304397597002284">bodlaender1998partial</a>,
Theorem 10, (iii)) iff <span class="math">\(G\)</span> has tw <span class="math">\(\leq 2\)</span>
(<a href="http://www.sciencedirect.com/science/article/pii/S0304397597002284">bodlaender1998partial</a>,
remark after Theorem 10) iff every <a href="https://en.wikipedia.org/wiki/Biconnected_component">biconnected
component</a> of <span class="math">\(G\)</span> is a
<a href="https://en.wikipedia.org/wiki/Series-parallel_graph">series-parallel graph</a> (<a href="http://www.sciencedirect.com/science/article/pii/S0304397597002284">bodlaender1998partial</a>,
Theorem 42). <a class="footnote-backref" href="#fnref:graph_tractability_bw2" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:graph_tractability_corneil">
<p>The original paper
is corneil2005relationship: D. G. Corneil, U. Rotics, <em>On the Relationship Between Clique-Width and
Treewidth</em>, 2005, but it is not available without
subscriptions. <a class="footnote-backref" href="#fnref:graph_tractability_corneil" rev="footnote" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:graph_tractability_makowsky">
<p>Observation 1 of
<a href="http://www.sciencedirect.com/science/article/pii/S0304397502004498">makowsky2003tree</a>
does not include the fact that T-closed implies S-closed (hence I-closed), but
I believe this to be an oversight. <a class="footnote-backref" href="#fnref:graph_tractability_makowsky" rev="footnote" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
<li id="fn:graph_tractability_minor">
<p>If <span class="math">\(G'\)</span> is not fixed, it is NP-hard, given two
graphs <span class="math">\(G'\)</span> and <span class="math">\(G\)</span>, to decide whether <span class="math">\(G'\)</span> is a minor of <span class="math">\(G\)</span>;
<a href="https://en.wikipedia.org/wiki/Graph_minor#Algorithms">Wikipedia</a>), <a class="footnote-backref" href="#fnref:graph_tractability_minor" rev="footnote" title="Jump back to footnote 4 in the text">↩</a></p>
</li>
<li id="fn:graph_tractability_existence">
<p>While this indeed shows the <em>existence</em> of a
quadratic test, to be able to <em>construct</em> this algorithm, we need to know the
actual finite set of forbidden minors. However, the Robertson-Seymour proof is
not constructive, and undecidability results are known about computing these
families in general; see
<a href="http://arxiv.org/abs/0902.3616">kreutzer2009algorithmic</a>, section 5.4.). <a class="footnote-backref" href="#fnref:graph_tractability_existence" rev="footnote" title="Jump back to footnote 5 in the text">↩</a></p>
</li>
</ol>
</div>a3nmSat, 20 Feb 2016 15:12:57 +0100tag:a3nm.net,2016-02-20:blog/graph_tractability.html