Constructor-based Inductive Theorem Prover (CITP)

A tool for proving inductive properties of software systems specified with constructor-based logics

The Constructor-based Inductive Theorem Prover (CITP) is a proof management tool built on top of a variation of conditional equational logic enhanced with many modern features.

The tool consists of two parts:

  • the core, which implements proof tactics, and
  • the user interface, which implements the parser, displays the results, and defines commands throught which users can interact with the tool.

CITP is implemented in Core Maude.


CITP consists of only one file, citp.maude (now at version 2.0). However, please note that you need to have Maude installed in order to use the tool.

Alternatively, you can obtain the full CITP distribution (including a set of example specifications and proofs) from its GitHub repository by using:

git clone


To use CITP, simply copy the file citp.maude to your current/working directory, open a terminal, and type:

maude citp.maude

If you are using the GitHub distribution, it suffices to open a terminal to the CITP directory and to type:

maude Tool/citp.maude

See the following PDF for the list of commands available in CITP, or read the Manual.


The followings are examples of specifications and proofs perfomed with CITP.

Simple proofs of two elementary inductive properties: the commutativity and associativity of the addition of natural numbers.

Learn more

This example shows one possible way of dealing with generic lists (with potentially void elements) in CITP, including operations for appending lists, computing their lengths, or reversing lists. We prove that the append operation is associative and that, moreover, both the length and the reverse operations distribute over append.

Learn more

Demonstrates the strength of the case analysis performed by CITP.

Learn more

One agent puts repeatedly pairs < bit, d > of bits and encoded datas into a channel which automatically decodes the information. When the agent reads < bit', d' > from the channel such that bit = bit', it is a confirmation that the data sent for decoding was received. In thad case, the agent stores the data received into a list structure, alternates the bit, and selects the next encoded data for sending. We assume that the channel is unreliable, meaning that the data in the channel may be lost or duplicated, but not exchanged or damaged.

Learn more

Assume that many agents (or processes) are competting for a common resource, but that at any given moment of time only one agent can use the resource. That is, the agents exclude or prevent each other from accessing the resource. A protocol that can gurantee this kind of mutual-exclusion property is called a mutual exclusion protocol (slides).

As in the QLOCK example above, another protocol that can guarantee such a mutual-exclusion property is TAS, which makes use of shared lock and an atomic test & set operation. A diagrammatic representation of an execution of the protocol can be found here.

The protocol consists of two processes, Sender and Receiver, each having a data buffer and a one-bit state. Sender and Receiver use two channels to communicate with each other, as they do not share any common memory: (a) a data channel from Sender to Receiver for sending bit-packet pairs, and (b) an acknowledgement channel from Receiver to Sender for sending single bits for confirmation. The protocol works as follows:

  • Initially, both channels are empty and Sender's bit is different from Receiver's bit.
  • Sender repeatedly writes bit-packet pairs < bit, pac > to the data channel, where bit is the Sender's bit and pac is the Sender's data to transmit. If the Sender receives bit from Receiver over the acknowledgement channel, then that is a confirmation that the packet sent has been delivered. In that case, Sender flips its bit and select the next packet to send.
  • Receiver writes its bit to the acknowledgement channel repeatedly. When Receiver reads a pair < bit, pac > such that bit is different from its bit, then it stores pac and flips its bit.
A snapshot of the protocol can be found here.

Consider a scenario where arbitrarily many PCs are connected to a Cloud in order to exchange messages – for simplicity, we treat these messages as natural values. Each of the PCs can fetch the latest value from the cloud, compare it with their own value, and update the Cloud or their own value depending on which is larger; see the Cloud in images.

A proof of the fact that every connected graph has a spanning tree.

Learn more