<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: antigones</title>
    <description>The latest articles on DEV Community by antigones (@antigones).</description>
    <link>https://dev.to/antigones</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F293259%2F32f021ca-2821-4259-910b-4be7be986912.png</url>
      <title>DEV Community: antigones</title>
      <link>https://dev.to/antigones</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antigones"/>
    <language>en</language>
    <item>
      <title>Matter protocol on a budget</title>
      <dc:creator>antigones</dc:creator>
      <pubDate>Sat, 11 Jan 2025 14:17:54 +0000</pubDate>
      <link>https://dev.to/antigones/matter-protocol-on-a-budget-32ph</link>
      <guid>https://dev.to/antigones/matter-protocol-on-a-budget-32ph</guid>
      <description>&lt;p&gt;&lt;em&gt;A Thread border router is not mandatory to interact with Matter devices&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Matter is a “super-standard” for IoT device interoperability: it promotes cooperation between smart things manufacturers and allows to control objects from the local network. It is relatively new, as its first specification version just came out in 2022.&lt;br&gt;
Even if the ability to get devices into market requires an attestation from Matter consortium, it is possible to study how Matter works at a relatively cheap cost.&lt;/p&gt;

&lt;p&gt;Matter works over IP-based technologies like Wi-Fi (“Matter-over-WiFi”) and Thread (“Matter-over-Thread”). While the first is generally used for the communication with devices transferring large amount of data (e.g. cameras), the latter is suitable for low-power devices requiring to transfer small amount of data (e.g. sensors or lights).&lt;br&gt;
Matter-over-Thread guarantees communications among a variety of devices and networks and to do so it requires two special “components”: a Thread border Router and a Radio Controller. The Thread Border Router handles communications among different kind of networks (eg. Wi-Fi, Ethernet and Thread) while the Radio Controller handles communication among devices.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does Matter work
&lt;/h2&gt;

&lt;p&gt;Adding a device to a network with Matter is super-easy: just scan its QR code and that’s it, the device is ready and configured. But what’s in that QR code?&lt;br&gt;
The QR code contains a lot of informations used to integrate the device into the domestic network such as the version of Matter standard, PIN and passkey to authenticate the device in the configuration phase, informations about the device and its vendor - namely the Vendor ID (VID) and Product ID (PID) – and security certifications of conformity to the CSA standard.&lt;br&gt;
In order to produce Matter devices, manufacturers must register to the Connectivity Standard Alliance (CSA), which manages the Matter protocol. It’s CSA to assign the VID to uniquely identify each manufacturer and then each manufacturer uniquely assign PID to its own devices (and so, the union of VID and PID uniquely identify the device). This ensures interoperability and guarantees that a device is coming from a verified manufacturer and that it respects the Matter standard.&lt;br&gt;
When the user scans the QR code (e.g. in the Google Home application on the phone), a pairing is initiated using PIN and informations stored in the QR code itself and the authentication certifies that the device is legitimate. The app also connects the device to the Wi-Fi network or the Thread network and when the pairing is completed, the device is part of the network, being accessible from all the other compatible devices and controllers.&lt;br&gt;
CSA also gives a generic VID for test and development purposes only so that developers can test Matter devices without a formal certification at no cost (and of course, that generic VID cannot be used for commercial products!)&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a device to the network: the commissioning
&lt;/h2&gt;

&lt;p&gt;The process of registering and adding a Matter device to a network is called commissioning.&lt;br&gt;
When the user wants to add a new device to network, the Google Home app (or another app capable to add Matter compatible devices) will act as commissioner. It will ask the user to scan the QR code (or to enter a PIN) printed on the device: at this point, the device is temporarily connected to the commissioner, cryptographic keys are exchanged to secure operational connection, informations to join the network are received and and the device is officially part of the network.&lt;/p&gt;
&lt;h2&gt;
  
  
  Removing a device from the network: the decommissioning
&lt;/h2&gt;

&lt;p&gt;Conversely, the process of removing a Matter device from the network is called decommissioning: it can be requested with an app (e.g. Google Home App) or from the device itself (e.g. pressing a button).&lt;br&gt;
When the device is decommissioned, cryptographic keys are invalidated and the device is reset. At this point the device cannot communicate anymore with the other devices in the network.&lt;/p&gt;
&lt;h2&gt;
  
  
  A low cost “hands-on” experiment with ESP32
&lt;/h2&gt;

&lt;p&gt;One way to play with Matter on a board without having to buy or configure a Thread border router is using an ESP32: Arduino core for ESP32 in fact gives us the capability to use Arduino IDE and the Arduino framework to deploy a Matter-enabled board.&lt;/p&gt;

&lt;p&gt;After installing ESP32 support in ArduinoIDE, just compile and upload the following example to the board (it has been readapted from example script in Arduino-esp32 repository from Espressif):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the snippet of code, the class of the device configures all the callable methods for the object and callbacks it responds to. In this case, since the board acts as a switch light:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MatterOnOffLight OnOffLight;
…
OnOffLight.toggle();
OnOffLight.onChange(setLightOnOff);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also note:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OnOffLight.updateAccessory();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This directive ensures that the current state of the light (e.g., whether it is ON or OFF) is correctly reflected on the device and on the controller. This could be useful if, for example, the user presses a button to toggle the light state: updateAccessory() would reflect that change in the Google Home App. Conversely, if the user toggle the light from the application, updateAccessory() would update device state accordingly.&lt;/p&gt;

&lt;p&gt;If you want to upload the snippet to ESP32, make sure to set the partition scheme to “Minimal SPIFFS”, to gain some space for the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zo38shwk04yvn1vktyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zo38shwk04yvn1vktyf.png" alt="Partitioning scheme to upload the sketch" width="269" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's time to add the device to the local network by choosing to add a "Matter enabled device":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12pxxptkccwfftv2cbnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12pxxptkccwfftv2cbnn.png" alt="Google Home Application " width="800" height="1733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and to enter the pin to begin the commissioning process (the pin is written in the serial output by the sketch, you can also scan the QR code at given the url):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb81l35k56ad0xo9noqo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb81l35k56ad0xo9noqo9.png" alt="" width="800" height="1733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the process ends (you should receive a message about the board not being certified but in this case is related to the fact that is just a development device) the board joined network!&lt;/p&gt;

&lt;p&gt;In the following video you can see the results of the experiment: the board is controlled from the Google Home mobile application. On the converse, a button on the board also acts as a "switch" lighting or shutting off the led and the status on the mobile app gets updated using Matter protocol.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WB-0if4cZdI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>iot</category>
      <category>esp32</category>
      <category>smarthome</category>
      <category>arduino</category>
    </item>
    <item>
      <title>Pumpkins in the Cloud: control your Jack-o-Lantern with Azure IoTHub!</title>
      <dc:creator>antigones</dc:creator>
      <pubDate>Mon, 30 Dec 2024 17:15:06 +0000</pubDate>
      <link>https://dev.to/antigones/pumpkins-in-the-cloud-control-your-jack-o-lantern-with-azure-iothub-32ei</link>
      <guid>https://dev.to/antigones/pumpkins-in-the-cloud-control-your-jack-o-lantern-with-azure-iothub-32ei</guid>
      <description>&lt;p&gt;With Halloween approaching, I had some fun 3D-printing my own pumpkin to put on display at night (see cover image!).&lt;/p&gt;

&lt;p&gt;The pumpkin itself was very nice, so I bought some IR remote controlled led tealights to give it the glow for some additional spooky amusement.&lt;/p&gt;

&lt;p&gt;The original idea was to just use a tealight led to light up without messing around with circuitry but I ended up putting it in the Cloud using Azure IoTHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IR remote controlled tea light led&lt;/li&gt;
&lt;li&gt;IR receiver&lt;/li&gt;
&lt;li&gt;IR emitter (AZDelivery KY-005)&lt;/li&gt;
&lt;li&gt;Esp8266&lt;/li&gt;
&lt;li&gt;Jumper cables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Understanding how to control the candle with IR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to control the tealight led, we have to know the command to send and we have to know, in fact, which commands the remote is sending to light and shut off the candle.&lt;/p&gt;

&lt;p&gt;For this step an Esp8266 would do the trick: it ensures compatibility with Arduino-IRRemote, a library to interact with IR emitter and receivers.&lt;/p&gt;

&lt;p&gt;The following circuit connects an IR receiver to the board and allows to read IR data from pin D5:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5h9g5ls312yqr71hj7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5h9g5ls312yqr71hj7w.png" alt="Connecting the IR receiver to the board" width="590" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following snippet of code decodes IR commands and prints them on the serial monitor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpz23jqzs6ak6lrn8995.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpz23jqzs6ak6lrn8995.png" alt="Code to manage IR receiver" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When pressing “on” and “off” buttons on the remote control, the library prints all the data received, along with the code to use to send the same command from an IR emitter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;21:32:55.011 -&amp;gt; received
21:32:55.011 -&amp;gt; FE01FF00
21:32:55.011 -&amp;gt; Protocol=NEC Address=0x0 Command=0x1 Raw-Data=0xFE01FF00 32 bits LSB first
21:32:55.142 -&amp;gt; Send with: IrSender.sendNEC(0x0, 0x1, &amp;lt;numberOfRepeats&amp;gt;);
21:32:55.174 -&amp;gt; received
21:32:55.208 -&amp;gt; 0
21:32:55.208 -&amp;gt; Protocol=NEC Address=0x0 Command=0x1 Repeat gap=39700us
21:32:55.274 -&amp;gt; received
21:32:55.274 -&amp;gt; 0
21:32:55.274 -&amp;gt; Protocol=NEC Address=0x0 Command=0x1 Repeat gap=96600us
21:33:01.148 -&amp;gt; received
21:33:01.148 -&amp;gt; FF00FF00
21:33:01.148 -&amp;gt; Protocol=NEC Address=0x0 Command=0x0 Raw-Data=0xFF00FF00 32 bits LSB first
21:33:01.246 -&amp;gt; Send with: IrSender.sendNEC(0x0, 0x0, &amp;lt;numberOfRepeats&amp;gt;);
21:33:01.609 -&amp;gt; received
21:33:01.609 -&amp;gt; 0
21:33:01.609 -&amp;gt; Protocol=UNKNOWN Hash=0x0 1 bits (incl. gap and start) received
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we have to use the statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IrSender.sendNEC(0x0, 0x1, &amp;lt;numberOfRepeats&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to light the candle and the statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IrSender.sendNEC(0x0, 0x0, &amp;lt;numberOfRepeats&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to turn it off.&lt;/p&gt;

&lt;p&gt;This part of the circuit can be unwired now (since it’s not going to be useful anymore) and we will integrate those commands in a script to control it through the microcontroller first and the from Cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controlling the candle, programmatically&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s now time to setup the circuit to emit an IR signal: as per the following schema, the data will be sent controlling D6 pin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foquqq2oz89pjjbnxgcey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foquqq2oz89pjjbnxgcey.png" alt="Circuit for IR emitter" width="644" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test the circuit, we can use serial communication to control the led emitter with a simple command interpreter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v523swues6n0f0gtbc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v523swues6n0f0gtbc4.png" alt="Code to manage IR emitter" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Putting the pumpkin in the Cloud&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To put the pumpkin in the Cloud we can use Azure IoTHub.&lt;/p&gt;

&lt;p&gt;Azure IoT Hub is a managed cloud service allowing bidirectional communication: cloud to device and device to cloud.&lt;/p&gt;

&lt;p&gt;Just to play, we can add a free-tier level service IoTHub service and then add a device:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fla0117oloaf3yqlll8kn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fla0117oloaf3yqlll8kn.png" alt="“Devices” menu in Azure IoTHub" width="362" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8xnzg96ps99njp7wm07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8xnzg96ps99njp7wm07.png" alt="Adding a device in Azure IoTHub" width="688" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here I added a device called “esp8266” and so I obtained a key to establish a bidirectional cloud-device communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcu0n2h8eu95ab06ckz0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcu0n2h8eu95ab06ckz0x.png" alt="Adding a device in IoTHub" width="446" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fury9mpkb1j8sdcni55dp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fury9mpkb1j8sdcni55dp.png" alt="Device list in IoTHub" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After configuring our IoTHub resources, we must take note of the following parameters (e.g. from Azure Portal):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3oz8a6idt7lrcpdpyjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3oz8a6idt7lrcpdpyjw.png" alt="Configuration parameters for the project" width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wi-Fi connection parameters are also required.&lt;/p&gt;

&lt;p&gt;To send message to the Cloud we can adapt the following example sketch: &lt;a href="https://github.com/Azure/azure-sdk-for-c-arduino/blob/main/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino" rel="noopener noreferrer"&gt;https://github.com/Azure/azure-sdk-for-c-arduino/blob/main/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can prepare a command interpreter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmjfp2v681fia7v7i0ab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmjfp2v681fia7v7i0ab.png" alt="The command intepreter" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we can adapt the callback for received messages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j6vfh5urmsk3s875ch1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j6vfh5urmsk3s875ch1.png" alt="Adapting the callback for received messages" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point we can use Azure Portal IoTHub interface to communicate with the device:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/hX6st8SFLtE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>iot</category>
      <category>esp8266</category>
      <category>azure</category>
      <category>iothub</category>
    </item>
    <item>
      <title>Going quantum: using Grover’s algorithm to generate worlds</title>
      <dc:creator>antigones</dc:creator>
      <pubDate>Sat, 06 Apr 2024 09:53:00 +0000</pubDate>
      <link>https://dev.to/antigones/going-quantum-using-grovers-algorithm-to-generate-worlds-133p</link>
      <guid>https://dev.to/antigones/going-quantum-using-grovers-algorithm-to-generate-worlds-133p</guid>
      <description>&lt;p&gt;&lt;a href="https://unsplash.com/it/@profwicks?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Image credits&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Formalizing the algorithm to generate worlds from a set of rules as a SAT problem opens the solution to a “quantum twist”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As seen in &lt;a href="https://dev.to/antigones/trying-to-bridge-the-gap-between-wfc-even-simpler-tiled-model-and-constraint-satisfaction-problem-csp-propositional-rules-1oka"&gt;the previous article&lt;/a&gt;, it is possible to express the problem of generating worlds from a set of rules as a boolean SAT problem.&lt;/p&gt;

&lt;p&gt;Grover’s algorithm can be used to solve such problems in the quantum computing domain (&lt;a href="https://qiskit-community.github.io/qiskit-algorithms/tutorials/06_grover.html"&gt;https://qiskit-community.github.io/qiskit-algorithms/tutorials/06_grover.html&lt;/a&gt;). Starting from a set of equiprobable states (Hadamard), Grover’s algorithm is a process capable of “making good states emerge” among all the others.&lt;/p&gt;

&lt;p&gt;Let’s try to generate a 1x2 map starting from the following constraints, expressed as propositional formulae:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  C_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_10, # C00 iif S_10 and not C_10 and not L_10
  C_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00,
  L_00: ~S_10 &amp;amp; (C_10 | L_10),
  L_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00,
  S_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_10,
  S_10: ~L_00 &amp;amp; (C_00 | S_00)
  (C_00 | L_00 | S_00), # you have to choose at least a value
  (C_10 | L_10 | S_10)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first need to express those constraints in Conjunctive Normal Form (CNF) and we can use sympy to obtain it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sympy.logic.boolalg import to_cnf
   c = to_cnf(model_ruleset)
   print(c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The formula expressed as CNF is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(L_00 | ~C_10) &amp;amp; (L_00 | ~L_10) &amp;amp; (S_10 | ~C_00) &amp;amp; (S_10 | ~S_00) &amp;amp; 
(C_00 | L_00 | S_00) &amp;amp; (C_10 | L_10 | S_10) &amp;amp; (~C_00 | ~C_10) &amp;amp; 
(~C_00 | ~L_10) &amp;amp; (~C_10 | ~S_00) &amp;amp; (~L_00 | ~S_10) &amp;amp; (~L_10 | ~S_00) &amp;amp; 
(C_00 | S_00 | ~S_10) &amp;amp; (C_10 | L_10 | ~L_00) &amp;amp; 
(L_00 | S_10 | ~C_00) &amp;amp; (L_00 | S_10 | ~C_10) &amp;amp; 
(L_00 | S_10 | ~L_10) &amp;amp; (L_00 | S_10 | ~S_00) &amp;amp; 
(C_00 | C_10 | L_10 | ~S_10) &amp;amp; (C_00 | C_10 | S_00 | ~L_00) &amp;amp; 
(C_00 | L_10 | S_00 | ~L_00) &amp;amp; (C_10 | L_10 | S_00 | ~S_10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s also remap variables with the following equivalence in order to use them with Qiskit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = L_00
b = L_10
c = C_00
d = C_10
e = S_00
f = S_10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it’s time to use Grover:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from qiskit import MissingOptionalLibraryError
from qiskit.tools.visualization import plot_histogram
from qiskit.primitives import Sampler
from qiskit.algorithms import Grover
from qiskit.circuit.library import PhaseOracle
from qiskit.algorithms import AmplificationProblem

expression = '(a | ~d) &amp;amp; (a | ~b) &amp;amp; (f | ~c) &amp;amp; (f | ~e) &amp;amp; (c | a | e) &amp;amp; (d | b | f) &amp;amp; (~c | ~d) &amp;amp; (~c | ~b) &amp;amp; (~d | ~e) &amp;amp; (~a | ~f) &amp;amp; (~b | ~e) &amp;amp; (c | e | ~f) &amp;amp; (d | b | ~a) &amp;amp; (a | f | ~c) &amp;amp; (a | f | ~d) &amp;amp; (a | f | ~b) &amp;amp; (a | f | ~e) &amp;amp; (c | d | b | ~f) &amp;amp; (c | d | e | ~a) &amp;amp; (c | b | e | ~a) &amp;amp; (d | b | e | ~f)'
try:
    oracle = PhaseOracle(expression)
    problem = AmplificationProblem(oracle, is_good_state=oracle.evaluate_bitstring)
    grover = Grover(sampler=Sampler())
    result = grover.amplify(problem)
    print(result)
    display(plot_histogram(result.circuit_results[0]))
except MissingOptionalLibraryError as ex:
    print(ex)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this script, PhaseOracle constructs a quantum circuit which is equivalent to the logical expression in input.&lt;/p&gt;

&lt;p&gt;AmplificationProblem builds a problem which is suitable to be elaborated by Grover’s algorithm and specifies a function to evaluate if a state is good.&lt;/p&gt;

&lt;p&gt;The script plots the following histogram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fieliwyxjahtu42ot3zr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fieliwyxjahtu42ot3zr4.png" alt="Quasi-probabilities for states" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The states seem to be mapped in the order they are encountered in the CNF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adbfce
000111
111000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the histogram isn’t so much clear, printing the quasi-probabilities as a dictionary shows that the two states with maximum quasi-probability are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S_10, C_00, S_00 (000111)
L_00, C_10, L_10 (111000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which are equivalent to the following rows in the truth table we previously found for this little 1x2 world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C_00,L_00,S_00,C_10,L_10,S_10
[False, True, False, True, True, False]
[True, False, True, False, False, True]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>quantumcomputing</category>
      <category>generativeart</category>
    </item>
    <item>
      <title>Trying to bridge the gap between WFC “Even Simpler Tiled Model” and Constraint Satisfaction Problem (CSP) propositional rules</title>
      <dc:creator>antigones</dc:creator>
      <pubDate>Fri, 15 Sep 2023 23:15:59 +0000</pubDate>
      <link>https://dev.to/antigones/trying-to-bridge-the-gap-between-wfc-even-simpler-tiled-model-and-constraint-satisfaction-problem-csp-propositional-rules-1oka</link>
      <guid>https://dev.to/antigones/trying-to-bridge-the-gap-between-wfc-even-simpler-tiled-model-and-constraint-satisfaction-problem-csp-propositional-rules-1oka</guid>
      <description>&lt;p&gt;(Photo by &lt;a href="https://unsplash.com/it/@rosssneddon?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Ross Sneddon&lt;/a&gt; on &lt;a href="https://unsplash.com/it/foto/sWlDOWk0Jp8?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Recently I tried to implement my own version of "Even Simpler Tiled Model" - a simplified version of Wave Function Collapse algorithm (source: &lt;a href="https://github.com/antigones/py-wfc-estm" rel="noopener noreferrer"&gt;https://github.com/antigones/py-wfc-estm&lt;/a&gt;) as explained in &lt;a href="https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;"Even Simpler Tiled Model", just like Wave Function Collapse, can be for example used to generate maps out of a set of rules. The idea is that it is possible to formalize those rules from a sample map and then use them to generate a new one, "propagating" reasoning about admissible/unadmissible values from tile to tile.&lt;/p&gt;

&lt;p&gt;Playing with my own implementation, a question arose: what defines a rule making a map difficult to collapse, when applying the Wave Function Collapse algorithm in its “Even Simpler Tiled Model” (ESTM) simplified form?&lt;br&gt;
Trying to answer this question, I ended up fallbacking the model to a propositional logic rules-related question and trying to formalize "Even Simpler Tiled Model" as a set of propositional logic rules.&lt;br&gt;
I took a sample map, defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLLLLLLL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLLLLLLL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLLLLLLL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLLLLLLL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLLCLLCC&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLLCSCCSS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLLCSSSSSS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LLCSSSSSSS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LCSSSSSSSS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CSSSSSSSSS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analyzing the sample map, the following rules came out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    'L': {
        (1, 0): {'L', 'C'}, 
        (0, 1): {'L', 'C'}, 
        (0, -1): {'L', 'C'}, 
        (-1, 0): {'L'}
    }, 

    'C': {
        (-1, 0): {'L'}, 
        (0, -1): {'S', 'L', 'C'}, 
        (1, 0): {'S'}, 
        (0, 1): {'S', 'L', 'C'}
    }, 

    'S': {
         (-1, 0): {'S', 'C'}, 
         (0, -1): {'S', 'C'}, 
         (1, 0): {'S'}, 
         (0, 1): {'S', 'C'}}
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rules informally state the following (see map at the beginning of this post):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Land can have a Land at North, East, South, West; Coast in the East, West, South&lt;/li&gt;
&lt;li&gt;Sea can have Coast or Sea in the North, Sea in the South, Coast or Sea at East and West&lt;/li&gt;
&lt;li&gt;Coast must have Land in the North; can have Land or Coast and East and West; must have Sea at south&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s rewrite this set of rules as a set of logic propositions.&lt;br&gt;
To accomplish this task and to be sure not to forget a rule, I wrote my own &lt;a href="https://gist.github.com/antigones/9f56e2e56c190953addf163f276863e9" rel="noopener noreferrer"&gt;model checker&lt;/a&gt; using SymPy.&lt;/p&gt;
&lt;h2&gt;
  
  
  An 1x2 sized world
&lt;/h2&gt;

&lt;p&gt;Since we have to rewrite the rules for each and every cell in the map, we first consider a 1x2 sized world.&lt;br&gt;
In this world, we define:&lt;/p&gt;

&lt;p&gt;L_00, “there is a land in (0,0)”&lt;br&gt;
C_00, “there is a coast in (0,0)”&lt;br&gt;
S_00, “there is sea in (0,0)”&lt;/p&gt;

&lt;p&gt;L_10, “there is a land in (1,0)”&lt;br&gt;
C_10, “there is a coast in (1,0)”&lt;br&gt;
S_10, “there is a sea in (1,0)”&lt;/p&gt;

&lt;p&gt;And the rules as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    C_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_10, 
    C_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00, 

    L_00: ~S_10 &amp;amp; (C_10 | L_10), # a Land in (0,0) only admit a C or a L in (1,0), does not admit Sea
    L_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00, 

    S_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_10, 
    S_10: ~L_00 &amp;amp; (C_00 | S_00)

    (C_00 | L_00 | S_00), # you have to choose at least a value
    (C_10 | L_10 | S_10)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(where ":" stands for "if and only if")&lt;/p&gt;

&lt;p&gt;To have a “valid” world map (i.e. a map respecting all the defined rules) we can only choose a set of truth values assignment satisfying all the rules (a model).&lt;br&gt;
The model checker prints all the assignments satisfying all the rules.&lt;/p&gt;

&lt;p&gt;For this small world, we have the two following models:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsn39r3jz5fx7ezhupjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsn39r3jz5fx7ezhupjf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reading the first row in the truth table, we can see that choosing Land in (0,0) pushes a Coast or a Land in (1,0). This gives us two perfectly valid maps in just one row:&lt;/p&gt;

&lt;p&gt;L&lt;br&gt;
C&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;L&lt;br&gt;
L&lt;/p&gt;

&lt;p&gt;Reading the second row in the truth table, we can see that choosing a Sea or a Coast in (0,0) only pushes a Sea in (1,0):&lt;/p&gt;

&lt;p&gt;CS&lt;br&gt;
S&lt;/p&gt;

&lt;p&gt;leading to the two (both valid) maps:&lt;/p&gt;

&lt;p&gt;C&lt;br&gt;
S&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;S&lt;br&gt;
S&lt;/p&gt;
&lt;h2&gt;
  
  
  A 2x2 map
&lt;/h2&gt;

&lt;p&gt;We can extend reasoning for maps of size beyond 1x2. Let’s consider a 2x2 world map.&lt;br&gt;
We can again write the propositional ruleset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    C_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_10 &amp;amp; (C_01 | L_01 | S_01), 
    C_01: S_11 &amp;amp; ~C_11 &amp;amp; ~L_11 &amp;amp; (C_00 | L_00 | S_00), 
    C_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00 &amp;amp; (C_11 | L_11 | S_11), 
    C_11: L_01 &amp;amp; ~C_01 &amp;amp; ~S_01 &amp;amp; (C_10 | L_10 | S_10), 

    L_00: ~S_01 &amp;amp; ~S_10 &amp;amp; (C_01 | L_01) &amp;amp; (C_10 | L_10), 
    L_01: ~S_00 &amp;amp; ~S_11 &amp;amp; (C_00 | L_00) &amp;amp; (C_11 | L_11), 
    L_10: L_00 &amp;amp; ~C_00 &amp;amp; ~S_00 &amp;amp; ~S_11 &amp;amp; (C_11 | L_11), 
    L_11: L_01 &amp;amp; ~C_01 &amp;amp; ~S_01 &amp;amp; ~S_10 &amp;amp; (C_10 | L_10), 

    S_00: S_10 &amp;amp; ~C_10 &amp;amp; ~L_01 &amp;amp; ~L_10 &amp;amp; (C_01 | S_01), 
    S_01: S_11 &amp;amp; ~C_11 &amp;amp; ~L_00 &amp;amp; ~L_11 &amp;amp; (C_00 | S_00), 
    S_10: ~L_00 &amp;amp; ~L_11 &amp;amp; (C_00 | S_00) &amp;amp; (C_11 | S_11), 
    S_11: ~L_01 &amp;amp; ~L_10 &amp;amp; (C_01 | S_01) &amp;amp; (C_10 | S_10),

    (C_00 | L_00 | S_00),
    (C_01 | L_01 | S_01),
    (C_10 | L_10 | S_10),
    (C_11 | L_11 | S_11)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use the model-checker to determine models:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tt6bayaax6f6itj7vyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tt6bayaax6f6itj7vyv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have four models here.&lt;br&gt;
Let's choose S in (1,1) - filtering all the models having S_11 to True:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop7jy0nhi5j14vpp4gvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop7jy0nhi5j14vpp4gvr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The truth table suggests the following situation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr69qba3ao4mglvj1k8su.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr69qba3ao4mglvj1k8su.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's choose L in (0,0):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8x8md7izffwrhaizk6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8x8md7izffwrhaizk6o.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The truth table evolves the map to the following one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13bmj8uug85u0r1fxkh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13bmj8uug85u0r1fxkh0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which is valid.&lt;/p&gt;

&lt;p&gt;If we take a step back and choose S in (0,0) then we have:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5rfztzxc52lqtkwpte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5rfztzxc52lqtkwpte.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which leads to the following (equivalent) set of maps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldwwrpp89dmkhe3da7ad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldwwrpp89dmkhe3da7ad.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which can be "unraveled" as the following four maps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa8ilzv23z7yk792d66d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa8ilzv23z7yk792d66d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Going up, 3x3 maps
&lt;/h2&gt;

&lt;p&gt;Using the model checker to generate/check rules for a 3x3 map, we obtain the following models:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9xc18pozwg7twdaz8ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9xc18pozwg7twdaz8ae.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's choose L for (2,2), to observe propagation as rule inference:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0brsjyavajbun9i3fpr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0brsjyavajbun9i3fpr0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leading to the map:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf5dm9i1y6spwnmydxw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf5dm9i1y6spwnmydxw2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which shows propagation of Land values across the tiles!&lt;/p&gt;

&lt;p&gt;Let's choose L in (2,0) - and note that it is interchangeable with a Coast:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdceykjjs4twr8jjv5mkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdceykjjs4twr8jjv5mkp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives two valid maps, where there is no difference in putting a Land or a Coast in (2,1):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sszi0nz993tf8mbl6o3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sszi0nz993tf8mbl6o3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A “very difficult” map
&lt;/h2&gt;

&lt;p&gt;Let’s stress things and consider the following sample map:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;img_hard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;KB&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SB&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and again, let’s write out the rules as logic proposition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    B_00: B_10 &amp;amp; ~B_01 &amp;amp; ~K_01 &amp;amp; ~K_10 &amp;amp; ~S_01 &amp;amp; ~S_10, 
    B_01: B_11 &amp;amp; ~B_00 &amp;amp; ~K_11 &amp;amp; ~S_11 &amp;amp; (K_00 | S_00), 
    B_10: B_00 &amp;amp; ~B_11 &amp;amp; ~K_00 &amp;amp; ~K_11 &amp;amp; ~S_00 &amp;amp; ~S_11, 
    B_11: B_01 &amp;amp; ~B_10 &amp;amp; ~K_01 &amp;amp; ~S_01 &amp;amp; (K_10 | S_10), 

    K_00: B_01 &amp;amp; S_10 &amp;amp; ~B_10 &amp;amp; ~K_01 &amp;amp; ~K_10 &amp;amp; ~S_01, 
    K_01: S_11 &amp;amp; ~B_00 &amp;amp; ~B_11 &amp;amp; ~K_00 &amp;amp; ~K_11 &amp;amp; ~S_00, 
    K_10: B_11 &amp;amp; ~B_00 &amp;amp; ~K_00 &amp;amp; ~K_11 &amp;amp; ~S_00 &amp;amp; ~S_11, 
    K_11: ~B_01 &amp;amp; ~B_10 &amp;amp; ~K_01 &amp;amp; ~K_10 &amp;amp; ~S_01 &amp;amp; ~S_10, 

    S_00: B_01 &amp;amp; ~B_10 &amp;amp; ~K_01 &amp;amp; ~K_10 &amp;amp; ~S_01 &amp;amp; ~S_10, 
    S_01: ~B_00 &amp;amp; ~B_11 &amp;amp; ~K_00 &amp;amp; ~K_11 &amp;amp; ~S_00 &amp;amp; ~S_11, 
    S_10: B_11 &amp;amp; K_00 &amp;amp; ~B_00 &amp;amp; ~K_11 &amp;amp; ~S_00 &amp;amp; ~S_11, 
    S_11: K_01 &amp;amp; ~B_01 &amp;amp; ~B_10 &amp;amp; ~K_10 &amp;amp; ~S_01 &amp;amp; ~S_10,

    (B_00 | K_00 | S_00),
    (B_01 | K_01 | S_01),
    (B_10 | K_10 | S_10),
    (B_11 | K_11 | S_11)    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model checker only returns 1 model:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp1wosemhqjyoq7t0hsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp1wosemhqjyoq7t0hsa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the only admissible solution.&lt;/p&gt;

&lt;p&gt;For a 3x3 map with the "hard" rules, we obtain UNSAT and the map cannot collapse.&lt;/p&gt;

</description>
      <category>python</category>
      <category>wavefunctioncollapse</category>
      <category>algorithms</category>
      <category>math</category>
    </item>
  </channel>
</rss>
