Determining max width available for Code 128 barcode - barcode

I'm looking for some sort of formula available to determine how much data I can fit on a Code 128 barcode that is no larger than a given width. The use case is a wristband that has a barcode printed on it.
Is there a minimum size required for the smallest bar for everything to be visible? Are there size ratios available anywhere (i.e. "Z takes up x times more space than 0")? I see that Code 128 supports compression of strings on numbers. More data is taken away by eliminating alpha characters, but do I end up getting more data in the same width by doing so?
EDIT: Going with that there is compression for number strings, the solution was to just test out 10, 12, 15, etc character strings. We decided to go with 12 as this is way more than enough for our use and scans very easily on a 1-inch wristband with leaving 10% on each side open. I'm still interested in the info requested though if anyone has insight.

All characters are equal relative width. Code 128C allows you to fit two numbers into a single character, but if you need to mix and match numbers and letters, you'll need to consistently have two or more pairs of numbers consecutive to make the added burden of the switch character worthwhile.
After a certain height, the vertical dimension does not matter, depending on the scanner.
The width of a character is directly proportional to its scanability and dependent upon the generator software, hardware and print media.
I measure density in characters per inch and with an inkjet printer I can get about 15½ characters per scannable inch. Packing them any denser and I suspect I would need a better printer and maybe a better scanner.
Here is a 40 character string encoded in Code128B at 15.6 cpi (43 characters including start, check and stop).
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/ASL/AADeAAAA/gAAAAIAAAD+AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAh6QEAZKdo54AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAcjEDAghkmFUAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAckoDA0TA9lYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjEDAjQrOn0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbkoDA3iPVH4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjUDAmZGozoAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbk4DAxdhexwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajUDAt82atYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajkDAr7LFAwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAATU4CA7CME0sAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARVICA/z3WM0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/ASL/AADeAAAA/gAAAAIAAAD+AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAh6QEAZKdo54AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjUDAlvFFR8AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAckoDA0TA9lYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjEDAjQrOn0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbkoDA3iPVH4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjUDAmZGozoAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbk4DAxdhexwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajUDAt82atYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajkDAr7LFAwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAATU4CA7CME0sAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARVICA/z3WM0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/ASL/AADeAAAA/gAAAAIAAAD+AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAh6QEAZKdo54AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjUDAlvFFR8AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAckoDA0TA9lYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjEDAjQrOn0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbkoDA3iPVH4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjUDAmZGozoAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbk4DAxdhexwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajUDAt82atYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajkDAr7LFAwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAATU4CA7CME0sAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARVICA/z3WM0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/ASL/AADeAAAA/gAAAAIAAAD+AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAh6QEAZKdo54AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjUDAlvFFR8AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAckoDA0TA9lYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjEDAjQrOn0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASVICA62zYxMAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbkoDA3iPVH4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjUDAmZGozoAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbk4DAxdhexwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAA/wAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAASU4CA+16cNAAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajUDAt82atYAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAajkDAr7LFAwAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAATU4CA7CME0sAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARVICA/z3WM0AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/ASL/AADeAAAA/gAAAAIAAAD+AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAh6QEAZKdo54AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAbjUDAlvFFR8AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAAAAAAAAAAAAP8AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAARTkCAqx1lb4AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAck4DAxY8F10AAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUUoCA+juoggAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/AQD/AAD/AAAAAQAAAAAAAAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAZjkDAtle3bIAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAAAAAAAAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAUU4CA1nljTgAAAAASUVORK5CYII=" width="4" height="30"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAQAAADLaIVbAAAANUlEQVQIHQEqANX/Af//AAABAAAA/wAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAck4DAxY8F10AAAAASUVORK5CYII=" width="4" height="30">

#Alex DeCamillo,
The ISO/IEC 15417 specification for the Code 128 symbology defines a formula to calculate the width which utilizes the number of characters, the width of the narrowest element and the required quiet zone to calculate the overall width. You can also use it with a constant width to calculate the required width of the minimum element and so forth. Unfortunately, I was not able to find this formula documented outside of the specification, so I cannot share the formula without violating the terms of the specification, but you can get the spec here: https://www.iso.org/standard/43896.html
Terry Warwick, Microsoft

Related

Printing a complex matrix Fortran

The complex matrix is declared this way:
complex(8) :: matrix(:,:)
How can I print this matrix with each element as: (a, b) or a+ib, and in a nxn format? (by that I mean as a square matrix, with a row per line, so there will be n rows and n columns)
This is the way I would print a real matrix with the format I want:
do i=1,n
do j=1,n
write(*, fmt="(f0.2, tr2)", advance="no") matrix(i,j)
end do
write(*, fmt="(a)") " "
end do
But I'm not sure how to translate this to a complex matrix
How can I print this matrix with each element as: (a, b)
Supposing you already know that (a b) is the default printing fotmat for complex type, Why isn't this just enough?
do j=1,n
write(*, *) matrix(:,j)
end do
The output would be something like:
(10.000000000000000,-20.000000000000000) (10.000000000000000,-20.000000000000000) (10.000000000000000,-20.000000000000000)
(10.000000000000000, 20.000000000000000) (10.000000000000000, 20.000000000000000) (10.000000000000000, 20.000000000000000)
If you want something more customized, you could try something like this (adjusting the field width and precision):
do j=1,n
write(*, "(*('('sf6.2xspf6.2x'i)':x))") matrix(:,j)
end do
That produces something like this:
( 10.00 -20.00 i) ( 10.00 -20.00 i) ( 10.00 -20.00 i)
( 10.00 +20.00 i) ( 10.00 +20.00 i) ( 10.00 +20.00 i)
So far this is what has worked for me. Taking into account Clinton's advice:
character(19) fmt
fmt = '(F7.2,"+",F7.2,"i")'
do i=1,n
do j=1,n
fmt(8:8) = MERGE('+',' ',imag(a(i,j)).gt.0)
write(*,fmt, advance="no") a(i,j)
end do
write(*, fmt="(a)") " "
end do
And the output is:
-0.26 -0.00i -0.00 -0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i
0.00+ 0.00i -0.25 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i
0.00 0.00i 0.00 0.00i -0.05 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i
0.00 0.00i 0.00 0.00i 0.00 0.00i -0.05 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i
0.00+ 0.00i -0.46 -0.00i -0.00+ 0.00i -0.00+ 0.00i -0.50 0.00i 0.00 -0.00i 0.00 0.00i -0.00 0.00i
0.32+ 0.00i -0.00+ 0.00i 0.00 -0.00i -0.00 -0.00i 0.00+ 0.00i -0.27 0.00i 0.00 0.00i 0.00 0.00i
-0.00+ 0.00i 0.00 -0.00i -0.00 -0.00i 0.24+ 0.00i 0.00 0.00i 0.00 0.00i -0.18 0.00i 0.00 0.00i
0.00 0.00i -0.00 -0.00i 0.24+ 0.00i 0.00 -0.00i 0.00 0.00i 0.00 0.00i 0.00 0.00i -0.18 0.00i
If someone has a better suggestion I'll be glad to hear it :)
Here is something that has worked in the past, it could be fine tuned quite a bit
!! compile and link with gfortran -I/usr/include -o PrintComplex PrintComplex.f90
Program PrintComplex
use, intrinsic :: iso_c_binding
implicit none
integer, parameter :: N=16
integer :: k
real (kind=c_double) :: val(N)
complex (kind=c_double_complex) :: in(N)
character(19) fmt
fmt = '(F7.2,"+",F7.2,"i")'
val=(/(sin(3.14159d0*float(k)/3.d0),k=1,N)/)
in=cmplx(val,-val/2)
print *,"in"
do k=1,N
fmt(8:8) = MERGE('+',' ',imag(in(k)).gt.0)
write(*,fmt)in(k)
end do
End Program PrintComplex
The output is:
in
0.87 -0.43i
0.87 -0.43i
0.00 -0.00i
-0.87+ 0.43i
-0.87+ 0.43i
-0.00+ 0.00i
0.87 -0.43i
0.87 -0.43i
0.00 -0.00i
-0.87+ 0.43i
-0.87+ 0.43i
-0.00+ 0.00i
0.87 -0.43i
0.87 -0.43i
0.00 -0.00i
-0.87+ 0.43i

Why is this ancestor code not working - Prolog

parent(jill, john).
parent(john, pam).
parent(pam, bob).
parent(tom, bob).
parent(tom, liz).
parent(bob, ann).
parent(bob, pat).
parent(pat, jim).
female(jill).
female(pam).
female(liz).
female(ann).
female(pat).
male(jim).
male(john).
male(tom).
male(bob).
mother(X,Y) :- female(X) , parent(X,Y).
father(X,Y) :- male(X), parent(X,Y).
offspring(X,Y) :- parent(Y,X).
sister(X,Y) :- female(X), female(Y), parent(Z,X), parent(Z,Y), not(X=Y).
ancestor(X, Y) :- parent(X,Z), ancestor(Z,Y).
This is the whole code plus some other stuff not related to the ancestor part. When I try to test it in swipl, the ancestor code gives me false. I am trying ancestor(pat,jim). and ancestor(X,jim). If I use ; instead of , in the ancestor code, it kind of works but repeats names when a person has both parents in the list.
In cases like this, trace is your friend:
?- trace.
true.
[trace] ?- ancestor(pat, jim).
Call: (8) ancestor(pat, jim) ? creep
Call: (9) parent(pat, _3162) ? creep
Exit: (9) parent(pat, jim) ? creep
Call: (9) ancestor(jim, jim) ? creep
Call: (10) parent(jim, _3162) ? creep
Fail: (10) parent(jim, _3162) ? creep
Fail: (9) ancestor(jim, jim) ? creep
Fail: (8) ancestor(pat, jim) ? creep
false.
See what happens? You defined ancestor(X,Y) as having two requirements: First, X must be the parent of some middleman Z, and then Z also needs to be an ancestor of Y. Since pat is the parent of jim, this requires jim to be his own ancestor, which he isn't.
One possible solution is to define an ancestor as either a direct parent or the parent of another ancestor:
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Let's test:
[trace] ?- ancestor(pat, jim).
Call: (8) ancestor(pat, jim) ? creep
Call: (9) parent(pat, jim) ? creep
Exit: (9) parent(pat, jim) ? creep
Exit: (8) ancestor(pat, jim) ? creep
So, we're good with pat and jim, because they are in a direct parent relation. What about the recursive case?
[trace] ?- ancestor(tom,pat).
Call: (8) ancestor(tom, pat) ? creep
Call: (9) parent(tom, pat) ? creep
Fail: (9) parent(tom, pat) ? creep
Redo: (8) ancestor(tom, pat) ? creep
Call: (9) parent(tom, _3168) ? creep
Exit: (9) parent(tom, bob) ? creep
Call: (9) ancestor(bob, pat) ? creep
Call: (10) parent(bob, pat) ? creep
Exit: (10) parent(bob, pat) ? creep
Exit: (9) ancestor(bob, pat) ? creep
Exit: (8) ancestor(tom, pat) ? creep
true .

Prolog: simple lexer/2

I need a small lexer/2 in prolog, currently I have
tokens(Z) --> "while", tokens(Y), {Z = [ttwhile | Y]}.
tokens(Z) --> "do", tokens(Y), {Z = [ttdo | Y]}.
tokens(Z) --> "endwhile", tokens(Y), {Z = [ttendwhile | Y]}.
tokens(Z) --> "repeat", tokens(Y), {Z = [ttrepeat | Y]}.
tokens(Z) --> "until", tokens(Y), {Z = [ttuntil | Y]}.
tokens(Z) --> "endrepeat", tokens(Y), {Z = [ttendrepeat | Y]}.
tokens(Z) --> "if", tokens(Y), {Z = [ttif | Y]}.
tokens(Z) --> "then", tokens(Y), {Z = [ttthen | Y]}.
tokens(Z) --> "else", tokens(Y), {Z = [ttelse | Y]}.
tokens(Z) --> "endif", tokens(Y), {Z = [ttendif | Y]}.
tokens(Z) --> "exit", tokens(Y), {Z = [ttexit | Y]}.
tokens(Z) --> "other", tokens(Y), {Z = [ttother | Y]}.
% Comparison operators.
tokens(Z) --> "==", tokens(Y), {Z = [equal | Y]}.
tokens(Z) --> "<>", tokens(Y), {Z = [notequal | Y]}.
% Assignment operator.
tokens(Z) --> ":=", tokens(Y), {Z = [:= | Y]}.
% Boolean constants and operators.
tokens(Z) --> "true", tokens(Y), {Z = [true | Y]}.
tokens(Z) --> "false", tokens(Y), {Z = [false | Y]}.
tokens(Z) --> "and", tokens(Y), {Z = [and | Y]}.
tokens(Z) --> "or", tokens(Y), {Z = [or | Y]}.
tokens(Z) --> " ", tokens(Y), {Z = Y}.
tokens(Z) --> " ", tokens(Y), {Z = Y}.
tokens(Z) --> [C], tokens(Y), {name(X, [C]), Z = [X | Y]}.
tokens(Z) --> [], {Z = []}.
Can anyone help me with the next step for lexer/2 so that when I call
lexer([while,a,==,b,do,abc,endwhile], R), I could get R = [ttwhile, a, equal, b, ttdo, abc, ttendwhile]?
Thank you very much.
well, this 'glue' - more or less - solves your request:
lexer(L, Tokens) :-
atomic_list_concat(L, ' ', A),
atom_codes(A, Cs),
phrase(tokens(Tokens), Cs).
?- lexer([while,a,==,b,do,abc,endwhile], R).
R = [ttwhile, a, equal, b, ttdo, a, b, c, ttendwhile] ;
R = [ttwhile, a, equal, b, ttdo, a, b, c, e|...] ;
but you should really rewrite in declarative style:
token(ttwhile) --> "while".
token(ttendwhile) --> "endwhile".
token(ttdo) --> "do".
%...
token(equal) --> "==".
token(notequal) --> "<>".
token(assign) --> ":=".
% this is wrong: symbols overlap with alphabetic tokens
token(N) --> [C], {atom_codes(N,[C])}.
tokens([]) --> [].
tokens(Ts) --> " ", tokens(Ts).
tokens([T|Ts]) --> token(T), tokens(Ts).
lexer(Cs, Tokens) :-
phrase(tokens(Tokens), Cs).
and call passing a codes list, a double quoted (or backquoted, if you're using SWI) string
?- lexer(`while abc endwhile`, R).
R = [ttwhile, a, b, c, ttendwhile] ;
R = [ttwhile, a, b, c, e, n, d, ttwhile] ;
...
edit
to tokenize names (well, only lowercase, for simplicity), replace the above token(N) --> [C], {atom_codes(N,[C])}. with
token(N) --> lower_case_chars(Cs), {Cs \= [], atom_codes(N,Cs)}.
lower_case_chars([C|Cs]) --> lower_case_char(C), lower_case_chars(Cs).
lower_case_chars([]) --> [].
lower_case_char(C) --> [C], {C>=0'a, C=<0'z}.
but it becomes a little verbose, when you add also upper_case_chars, digits, etc... it's worth to generalize, passing the characters range boundary, or use code_type/2:
token(N) --> csymf(C), csyms(Cs), {atom_codes(N,[C|Cs])}.
csymf(C) --> [C], {code_type(C,csymf)}.
csyms([C|Cs]) --> [C], {code_type(C,csym)}, csyms(Cs).
csyms([]) --> [].
What about the following solution?
lexer(I, O) :-
tokens(O, I, []).
But calling lexer() in this way
lexer("while a == b do abc endwhile", R)
I add a suggestion: rewrite tokens() in this way
tokens([ttwhile | Z]) --> "while", tokens(Z).
tokens([ttdo | Z]) --> "do", tokens(Z).
tokens([endwhile | Z]) --> "endwhile", tokens(Z).
tokens([ttrepeat | Z]) --> "repeat", tokens(Z).
tokens([ttuntil | Z]) --> "until", tokens(Z).
tokens([ttendrepeat | Z]) --> "endrepeat", tokens(Z).
tokens([if | Z]) --> "if", tokens(Z).
tokens([then |Z]) --> "then", tokens(Z).
tokens([ttelse | Z]) --> "else", tokens(Z).
tokens([ttendif | Z]) --> "endif", tokens(Z).
tokens([ttexit | Z]) --> "exit", tokens(Z).
tokens([ttother | Z]) --> "other", tokens(Z).
% Comparison operators.
tokens([equal | Z]) --> "==", tokens(Z).
tokens([notequal | Z]) --> "<>", tokens(Z).
% Assignment operator.
tokens([:= | Z]) --> ":=", tokens(Z).
% Boolean constants and operators.
tokens([true | Z]) --> "true", tokens(Z).
tokens([false | Z]) --> "false", tokens(Z).
tokens([and | Z]) --> "and", tokens(Z).
tokens([or | Z]) --> "or", tokens(Z).
tokens(Z) --> " ", tokens(Z).
tokens([X | Z]) --> [C], tokens(Z), {name(X, [C])}.
tokens([]) --> [].
P.s.: sorry for my bad English.

Prolog - Consult actually cleans current state?

I had the following code for customer creation and listing:
:-dynamic customer/2.
load:-consult('C:\\customers.txt').
save:-tell('C:\\customers.txt'), listing(customer), told.
%New customer
new_customer:-write("Name: "), read(Name),
customer_code(Code), asserta(customer(Code, Name)), save.
customer_code(Code):- customer(C, _, _, _), Code is C + 1.
customer_code(1).
So far, so good. The problem is, when trying to do more complex search, filtering and reports in general, I had to use retract to clean the current memory state of the customers.
So, before any listing, I tend to consult the file again (calling load):
list_customers:- load, listing(customer).
What goes wrong here is that more times than not, this new load will cause the listing to repeat the last customer added to the database.
Eg:
C:\customers.txt:
:-dynamic customers/2
(2, 'John')
(1, 'Alicia')
listing(customers):
(2, 'John')
(2, 'John')
(1, 'Alicia')
I've been able to avoid this by using retractall before consulting:
load:- reatractall(customer(_,_)), consult('C:\\customers.txt').
Is this a good/bad practice? I don't quite understand what's going on here or why this solves the problem.
The consult predicate, as stated in the documentation in a rather obscure place that references to a deprecated reconsult clause, states that it will reload the clauses that where loaded from the file.
What does this mean in this case?
When you first create the entries in the text file, the clauses that where loaded from the file and the clauses that you created are the same.
The problem arises when you add a new entry. Let's check this with an example to make things clear:
1) You load the file with consult:
Now your database and the file will contain the same clauses:
customers.txt:
:- dynamic customer/2.
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
So far, so good.
2) You add a new customer and save it to the file using tell / told:
customers.txt:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Still, no issues. Here comes the real problem:
3) You reload the file:
customers.txt:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(5, 'Juan').
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Okay, what happened here? If you remember, we previously saw that consult reload clauses that where loaded from the file.
So, the clauses we reloaded are:
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
This leaves us with a clause, customer(5, 'Juan'), that wasn't loaded from the file the first time. So now we have to add it to our database, thus resulting in:
customer(5, 'Juan').
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').

Decision Tree in Prolog

The following is my Prolog program for a decision tree which gives output oil or telecommunication or computers (investment option for the person:oil-high risk,telecommunication- moderate risk,computer-stable risk) depending on the input given name,marital_status, income and mortgage. But I am getting an error!
moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I),
I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M),M=married,ask_income(X,I), I>50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000,
ask_age(X,A),A>50,!.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000,
ask_age(X,A),A=<50,!.
invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.
main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital
status:married or single?'), read(Y), asserta(marital_status(X,Y)).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), read(Y),
asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)),write('what is your remaining mortgage?'),
read(Z), asserta(mortgage(X,Z)).
ask_age(X,A):-not(age(X,A)).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), asserta(age(X,A)).
As SWI-Prolog is telling you, marital_status/2 is not defined. You reference it in:
ask_marital_status(X,Y) :- marital_status(X,Y).
But you never defined it anywhere.
This is what I get when I try to compile:
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning:
Warning: age/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:80:16: 1-st clause of ask_age/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:81:19: 2-nd clause of ask_age/2
Warning: income/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:70:19: 1-st clause of ask_income/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:71:22: 2-nd clause of ask_income/2
Warning: marital_status/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:64:4: 1-st clause of ask_marital_status/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:66:8: 2-nd clause of ask_marital_status/2
Warning: mortgage/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:75:21: 1-st clause of ask_mortgage/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:76:24: 2-nd clause of ask_mortgage/2
true.
So, I follow the recommendation in the first two lines of the warning message an add the following to the top of the file:
:- dynamic age/2, income/2, marital_status/2, mortgage/2.
I also corrected the mistake in the definition of ask_age/2. With this program (with corrected formatting):
:- dynamic age/2, income/2, marital_status/2, mortgage/2.
moderate_risk(X) :-
ask_marital_status(X,Y),
Y=married,
ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z=<50000,
!.
moderate_risk(X) :-
ask_marital_status(X,M),
M=married,
ask_income(X,I), I>50000,
!.
moderate_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I=<35000,
!.
stable_risk(X) :-
ask_marital_status(X,M),
M=married,
ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z>50000,
!.
stable_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I>35000,
ask_age(X,A), A>50,
!.
high_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I>35000,
ask_age(X,A),A=<50,
!.
invest(X,oil) :-
stable_risk(X),
!.
invest(X,telecommunications) :-
moderate_risk(X),
!.
invest(X,computers) :-
high_risk(X),
!.
main(X,Z) :-
var(X),
write('what is your name?'), read(X),
invest(X,Z),
!.
main(X,Z) :-
invest(X,Z),
!.
ask_marital_status(X,Y) :-
marital_status(X,Y).
ask_marital_status(X,Y) :-
not(marital_status(X,Y)),
write('what is your marital status:married or single?'), read(Y),
asserta(marital_status(X,Y)).
ask_income(X,Y) :- income(X,Y).
ask_income(X,Y) :- \+ income(X,Y),
write('what is your annual income?'), read(Y),
asserta(income(X,Y)).
ask_mortgage(X,Z) :- mortgage(X,Z).
ask_mortgage(X,Z) :- \+ mortgage(X,Z),
write('what is your remaining mortgage?'), read(Z),
asserta(mortgage(X,Z)).
ask_age(X,A) :- age(X,A).
ask_age(X,A) :- \+ age(X,A),
write('what is your age?'), read(A),
asserta(age(X,A)).
You will notice that you have a silly amount of cuts. Most of them are probably unnecessary. Especially cuts at the end of clause bodies are always never meant to be there. You can try and remove all cuts at ends of clauses and see if this changes the behaviour of your program.
I can now load and run the code with ?- main(boris, Z)..

Resources