Reproducing Copycat: a Python Re-implementation of a Classic Model of Analogy-Making

Over the last months, I have been working on a reproduction of Melanie Mitchell’s and Douglas Hofstadter’s computer model of analogy-making called Copycat1. This model works within the micro-domain of string transformations but is intended as a general model of the way that people flexibly use concepts and make concept mappings while they think about the world.

A typical problem is presented to Copycat as a string: “abc → abd ==> ijk → ?” which means “if abc is transformed to abd, then what is ijk transformed to?”. Copycat finds descriptions, bonds between letters, groupings, concept mappings, and correspondences between letters, that could be used to generate a rule for making the analogous transformation. For example, Copycat normally recognizes that d is the successor of c and these are the rightmost letter in their respective strings. It therefore generates a rule “replace the rightmost letter with its successor” and outputs the answer ijl. Occasionally it might produce the answer ijd based on a more shallow analogy “replace the rightmost letter with d“.

A Cattycam view of Copycat’s workspace

Copycat can recognize even deeper analogies based on more concept mappings. For example, in the problem “abc → abd ==> mrrjjj → ?”, it is able to map alphabetic succession onto numerical succession applied to the length of groups of the same letter and output mrrjjjj (with 4 js instead of 3). In the problem “abc → abd ==> xyz → ?”, Copycat can make use of its opposite concept and map alphabetic successors onto alphabetic predecessors and right onto left resulting in the answer wyz.

I initially found Copycat interesting as it displays an ability to use concepts flexibly and because its temperature mechanism – which simultaneously measures the quality of structures in its workspace and affects the level of randomness in its architecture – allows Copycat to regulate its own processing and avoid brute force search for solutions. When the workspace is incoherent or disconnected, temperature increases, decisions are more random and the search effectively becomes more broad; when the workspace is well-structured, temperature decreases, decisions are more deterministic, and the search becomes more directed.

Copycat’s architecture involves a Workspace where its structures are built; a network of concepts which become active when relevant in the workspace or via spreading activation; and codelets (micro-agents) which make incremental changes to the workspace and are scheduled stochastically by the coderack. Decisions result from circumstances in the workspace, slipnet activations, and the degree of randomness determined by the temperature. Unlike in contemporary agentic systems built around LLMs, there is no centralized orchestrator. I think this style of architecture would therefore make an interesting candidate for a more flexible alternative to systems which depend on large, often proprietary or opaque transformer models.

Unfortunately, it has been difficult to make progress on research in this direction, because Copycat and related models developed by the Fluid Analogies Research Group are often difficult to run within contemporary programming environments. The original version of Copycat was written in Common Lisp and requires dependencies that no longer exist.

I have built this reproduction of Copycat as a model to be run within Cattykit, the Python library I am developing for micro-agent models of artificial intelligence. The internal working of this Copycat re-implementation can be viewed using the tool Cattycam, which I am developing to help in debugging such models.

I have tested that my reproduction of Copycat broadly matches the original by comparing its distribution of answers to a set of 29 problems with those reported by Mitchell for the original implementation. I have also compared the final temperatures and codelets run (by comparing with the means and standard errors reported by Mitchell). Broadly, the answers and temperatures generated by my reproduction match with those generated by the original version, but my version often runs more codelets. A lot of this seems to be down to my decision to use floating point numbers to represent temperature and concept activations (among other values) whereas the original used integers between 0 and 100. I have written up a full description of my reproduction experiments here.

If you would like to try running Copycat on your own computer, install Cattykit and Cattycam:

pip install cattykit cattycam

Then install Copycat by running:

cattykit install copycat

You can try out an analogy problem by running a basic script:

from cattykit import load_model
from cattykit.logging import CattycamLogger

cattycam_logger = CattycamLogger("history.sqlite", "copycat")

copycat = load_model(
    "copycat",
    config={"seed": 1234},
    logger=cattycam_logger,
)

copycat.solve("abc -> abd ==> ijk -> ?")
copycat.solve("abc -> abd ==> xyz -> ?")
...

Then, to view how the model worked out an answer to each problem, run Cattycam and an interactive application will open in your web browser:

cattycam path/to/history.sqlite

The Cattycam interface showing Copycat’s run history

I hope you enjoy playing with this classic model of analogy making. Watch this space for further developments of the Cattykit library!

Footnotes

  1. Copycat is described in full in Mitchell’s book Analogy-Making as Perception. ↩