<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4686393050407685865</id><updated>2024-11-02T16:35:36.061-07:00</updated><category term="travelling salesman"/><category term="Business"/><category term="Chat"/><category term="Citizenship"/><category term="DevOps"/><category term="Facebook"/><category term="Feed"/><category term="IT"/><category term="Illegal"/><category term="Mexican"/><category term="Technology"/><category term="Twitter"/><category term="Windows"/><category term="experience"/><category term="fail"/><category term="fluxbox"/><category term="howto"/><category term="linux"/><category term="monte carlo"/><category term="nsa"/><category term="opinion"/><category term="privacy"/><category term="programming language"/><category term="ratpoison"/><category term="share"/><category term="tag cloud"/><category term="user data"/><category term="window manager"/><title type='text'>The Scholar</title><subtitle type='html'>Featuring many interesting topics in one place, including politics, philosophy, logic, math, comedy, music, and literature.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4107073395868072087</id><published>2018-03-17T07:50:00.001-07:00</published><updated>2018-03-17T07:50:23.593-07:00</updated><title type='text'>In Defense of the Hosted Language: Why Golang isn&#39;t the Catch-all, End-all</title><content type='html'>When I first heard about Golang, I sincerely thought the JVM was obsolete. Its day was past in my head. After all, when I wrote in Go, I &lt;i&gt;felt&lt;/i&gt; like I was writing in Java or Python, because it was garbage collected. At the same time, since it was cross-compilable, it was as portable as Java, but I didn&#39;t need to install a run time first. As a DevOps engineer, I really saw the benefit. I still do.&lt;br /&gt;
&lt;br /&gt;
But as I have learned, it has its drawbacks. For example, say I want to write a GUI application. With the JVM, I can do all of it in pure Java. (Not that you would want to do this, but bear with me.) But I can&#39;t do it in Golang without using CGo. Why? Well, this is because you need to interact with native code to write a GUI because assembly is the language in which computer graphics speak (ish -- I know I&#39;m glossing over details) and that is most easily interfaced with using a native language like C, C++ or Rust. With Java, I can bake that native code into the JVM, then call that native code using Java. With golang, I&#39;m out of luck, precisely because golang is compiled and needs to bring all of its dependencies with it. With the JVM or similar runtimes, you can spend lots of time making sure a runtime compiles correctly on a particular system, then make that runtime widely available. After that, programming for it becomes really easy. I believe this is why Java&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_Native_Interface&quot;&gt;JNI&lt;/a&gt; is discussed much less (and, me guessing again, is probably used less) than golang&#39;s &lt;a href=&quot;https://blog.golang.org/c-go-cgo&quot;&gt;CGo&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Once you use CGo, &lt;a href=&quot;https://dave.cheney.net/2016/01/18/cgo-is-not-go&quot;&gt;you lose golang&#39;s benefits over java&lt;/a&gt; in the first place. In all honesty, I really like having exceptions and generics.&lt;br /&gt;
&lt;br /&gt;
If I&#39;m a DevOps engineer building a cross-platform desktop application, I really like the idea of using Go -- until we talk about CGo. At that point, I&#39;m choosing between packaging a JVM in with my application (think Windows), or I&#39;m compiling on every target OS for all of my libraries. The former is a lot of up-front work, but after that becomes easy; the 
latter is easier, but with lots of corner cases that will pay dividends 
in annoying bugs over time.&lt;br /&gt;
&lt;br /&gt;
Even as such an engineer deploying an app to the Kubernetes cluster, 
CGo means that I have to really make sure I compile for the right 
version of glibc, which can be tricky and painful. I&#39;d much rather deploy a Java app at that point.&lt;br /&gt;
&lt;br /&gt;
So then I have come to the conclusion that &lt;a href=&quot;https://clojure.org/about/rationale&quot;&gt;Rich Hickey wasn&#39;t wrong&lt;/a&gt;: VMs offer some really nice features that you just can&#39;t get without them. They do present up-front distribution costs at times; but if you can nail that, your developers can continue to program and be productive, and have a clear, uniform path for getting features into the app without having to worry about the Cgo library land mines. (Full disclosure: I&#39;m a Clojure fan. See what I did there?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4107073395868072087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2018/03/in-defense-of-hosted-language-why.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4107073395868072087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4107073395868072087'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2018/03/in-defense-of-hosted-language-why.html' title='In Defense of the Hosted Language: Why Golang isn&#39;t the Catch-all, End-all'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-2048366641017536803</id><published>2018-02-22T18:34:00.003-08:00</published><updated>2018-02-22T18:34:26.017-08:00</updated><title type='text'>Making Kubernetes Approachable: We Need Strong Distributions</title><content type='html'>Linux, in its raw form, is a complicated enough system as to not feel approachable by normal users. A nice distribution of it is easy enough to install and use, sure; but installing Gentoo Linux, for example, is much more difficult. The value of mainstream distributions of Linux such as Ubuntu or CentOS is that they made the installation, use, and upgrade path on a linux system approachable.&lt;br /&gt;
&lt;br /&gt;
They do this in three ways:&lt;br /&gt;
&lt;br /&gt;
1. They make installation of an entire system simple.&lt;br /&gt;
2. They make a lot of opinionated design decisions in an effort to make things simple. For example, most Linux distros choose what the init process should be for you (systemd, init, upstart).&lt;br /&gt;
3. They provide a clean upgrade path for all parts of the system, from the apps installed on the system down to the barebones part of the system (think linux kernel) through the use of a system package manager. &lt;br /&gt;
&lt;br /&gt;
Now let&#39;s take those ideas to the wildly-popular-but-still-emerging technology, Kubernetes. Right now, how approachable is a kubernetes install?&lt;br /&gt;
&lt;br /&gt;
Well, the first point is addressed well enough I think. Quasi-&quot;distributions&quot; such as kubeadm, kubespray and kubeform allow you to install the system simply.&lt;br /&gt;
&lt;br /&gt;
They start to fall short when we get to point #2, though. Kubernetes does not prescribe how to set up DNS inside the cluster, and doesn&#39;t prescribe what kind of Ingress should be used. However, in my opinion at least, Kubernetes is most often unusable without these components. Other components that you&#39;ll almost always want include network overlay (many use flannel, ipsec, or calico for this). Most Kubernetes distributions supply these needs, but even the bigger ones like Rancher don&#39;t supply what should be used as an Ingress. Kubeform, or at least its Roadmap, is getting closer to this.&lt;br /&gt;
&lt;br /&gt;
However, I feel like they all fall short in category #3, making an upgrade smooth by using an explicit system for dependency management. I have just tried upgrading kubernetes in Rancher, it is an absolute breeze compared to others I&#39;ve seen on the internet; however, you still have to follow its docs to upgrade certain components before other components manually. Other distributions of Kubernetes likewise provide set-by-step docs. If Kubernetes is to really become approachable, this is not enough. I can follow docs to install Gentoo as well, but this is not nearly as approachable as the simple commands ``sudo apt-get update; sudo apt-get dist-upgrade``. There is no explicit dependency management for the entire Kubernetes system. There certainly is no system akin to aptitude or rpm that tracks dependencies for parts of the kubernetes system itself and the apps that run on it alike. The ansible roles and scripts provided by kubespray and kubeforms do not satisfy here. Kubernetes would take a great leap forward if such a system were ever developed.&lt;br /&gt;
&lt;br /&gt;
And before you say &quot;Helm!&quot;, helm is simply not built for this.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/2048366641017536803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2018/02/making-kubernetes-approachable-we-need.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/2048366641017536803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/2048366641017536803'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2018/02/making-kubernetes-approachable-we-need.html' title='Making Kubernetes Approachable: We Need Strong Distributions'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-7733867584267939348</id><published>2017-08-05T13:05:00.003-07:00</published><updated>2017-08-05T13:06:25.845-07:00</updated><title type='text'>On Package Manager Architectures, Part I</title><content type='html'>I am sort of a package manager junky. I even wrote my own package manager, capable of managing dependencies across programming language boundaries, called &lt;a href=&quot;https://degasolv.readthedocs.io/&quot;&gt;Degasolv&lt;/a&gt;. During the course of my travels, I&#39;ve noticed some very significant things about package management architecture.&lt;br /&gt;
&lt;br /&gt;
There are really three different kinds of package managers. Each fundamental type of package manager makes trade-offs. Each type is fairly successful in its own ecosystem. It is instructive to point out the differences.&lt;br /&gt;
&lt;br /&gt;
Here I will treat the two most significant. The third type deserves its own blog post (assuming I get to it). For the curious, it includes &lt;a href=&quot;https://en.wikipedia.org/wiki/Apache_Ivy&quot;&gt;ivy&lt;/a&gt; and &lt;a href=&quot;https://maven.apache.org/&quot;&gt;maven&lt;/a&gt;, and I will discuss this one later.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
The Main Differences&lt;/h3&gt;
&lt;br /&gt;
The first type is that of the system package manager. The archetype of this category is &lt;a href=&quot;https://fedoraproject.org/wiki/Yum&quot;&gt;YUM&lt;/a&gt;, and more recently, &lt;a href=&quot;https://fedoraproject.org/wiki/DNF?rd=Dnf&quot;&gt;DNF&lt;/a&gt;. In this model, the following facts are true:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Packages install files into a shared file system, and are shared resources. Only one package of each package name may exist in an installation at any given time. Packages may NOT share ownership of a particular file (RPM is actually pretty strict about this), and generally do not share resources.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Because of this, there must be agreement on package semantics. Since the &quot;libc&quot; package is a shared resource, all packages must agree on what &quot;libc&quot; means. This means that all packages must agree on an acceptable version of libc.&lt;/li&gt;
&lt;li&gt;All packages are owned by the system, NOT by other packages. Java apps do not specify how to configure Java, for example. The systems administrator is in charge of configuring the Java package, not other packages that rely on Java.&lt;/li&gt;
&lt;li&gt;No domain knowledge exists at the package level of the &quot;type&quot; of thing being installed; all DNF knows about are files. Packages installing a C shared library and packages installing a tomcat service are in some sense created equal.&lt;/li&gt;
&lt;li&gt;At at least a theoretical level, circular dependencies are possible. It is possible to resolve the dependency of &quot;a -&amp;gt; b -&amp;gt; a&quot;, by installing both &quot;a&quot; and &quot;b&quot;.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Contrast this with a &amp;nbsp;manager like &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;NPM&lt;/a&gt;. NPM is the archetypal package manager of the second type of package managers, a class which I will call the &quot;hierarchical package managers&quot;. Others include &lt;a href=&quot;https://github.com/whyrusleeping/gx&quot;&gt;GX&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;https://helm.sh/&quot;&gt;Helm&lt;/a&gt;. It is very popular, and very different:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;All packages are installed relative to the package requiring them. Therefore, packages are not shared resources. Package installations are only used by the package that depends on them. There are no shared resources anywhere (in theory); if A relies on B, it is the only package relying on B. If, for example, package A relies on both B and C, and package B relies on package C, then package B will get its own copy of C installed relative to B and package A will get its own copy of C installed relative to A. A and B do not share C at all.&lt;/li&gt;
&lt;li&gt;Because of this, no agreement on package semantics is necessary. A and B in the example above do not need to agree on what &quot;C&quot; means; A can use 2.0 of package C and B can use 1.0 of package C and no one cares.&lt;/li&gt;
&lt;li&gt;In this sense, packages are &quot;owned&quot; by parent packages. This can be seen in this category of package manager with the Helm pacakge manager. Values in the sub-packages&#39; values.yaml (the package&#39;s configuration file) may be overridden by values in a parent package. &amp;nbsp;Ownership, the sort of &quot;care and feeding&quot; that the depended on package needs to work, is provided by the depending package.&lt;/li&gt;
&lt;li&gt;The package manager takes advantage heavily of domain knowledge. It makes assumptions about what is being installed and only makes sense in the context of some programming language or system, such as Javascript in NPM&#39;s case or Kubernetes in Helm&#39;s case.&lt;/li&gt;
&lt;li&gt;Because packages are installed relative to the packages that rely on them, circular dependencies are not possible&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
On Shared Resources&lt;/h3&gt;
&lt;div&gt;
The most interesting point in the above discussion, in my opinion, is that of whether or not a package is a shared resource. Consider &lt;a href=&quot;https://github.com/kubernetes/helm/issues/2762&quot;&gt;this bug I filed with the Helm chart package manager&lt;/a&gt;. In it, I show that although the package manager Helm is of the second type, and therefore assumes that packages (in Helm nomenclature, &quot;charts&quot;) are not shared resources, this is not always the case. In the default case, packages create services using names that assume that there exists only one package of a certain name in any given release.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In short, in order for a package manager to be of the second type, and for that to work, packages must truly and in every way must not be shared resources, ever. There are subtle corner cases in every language or system where this is simply not true.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Consider the example of two packages with a &quot;mutual friend&quot; package. In this scenario, Package Alice and Package Ben have a mutual friend, Package Cat. Alice talks to Cat and asks Cat to tell her the right amount of money needed to buy a horse. Alice then asks Ben to buy a horse for her, giving him needed money. Ben then asks Cat if the money given to buy the horse is enough.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
The above example is contrived and tells the story of the classic diamond: Package A, which relies on Package B and Package C. Package B also relies on Package C.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now consider if these packages were NPM packages. Package B&#39;s Package C is installed relative to B, and could be at an entirely different version than Package A&#39;s Package C. This version difference is perhaps breaking. So, what may end up happening is that Package Alice asks Cat how much money to use for buying a horse, and Cat&#39;s methods of figuring out how much money that is may have completely changed between Cat 2.0 and Cat 3.0 . So Alice&#39;s Cat 2.0 says she needs $1000, and she gives this to Ben. Ben asks Cat 3.0 if that&#39;s enough, but Cat 3.0 says &quot;no&quot;. Now Ben gives an error and no one knows why.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This example shows that even though Ben and Alice do not share the same Cat package, they are sharing her as a resource. They rely on her expertise and believe that whatever Cat says is right. Therefore NPM&#39;s fundamental assumption that Cat is not a shared resource is violated. The developers of Alice don&#39;t talk to Ben&#39;s developers, but they&#39;re both in the same community and both have been told to use package Cat for all things horse. It&#39;s simply the de facto solution in the community.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Though contrived, this is a real problem. NPM tried to fix this by introducing &quot;&lt;a href=&quot;https://blog.domenic.me/peer-dependencies/&quot;&gt;peerDependencies&lt;/a&gt;&quot; for those packages where this really matters, and I think this isn&#39;t a bad plan. It allows packages to use the hierarchical method of managing dependencies, assuming packages aren&#39;t shared resources, for the general case, while allowing them to specify hard requirements when problems arise.&lt;/div&gt;
&lt;h3&gt;
On Ownership&lt;/h3&gt;
&lt;div&gt;
A second fundamental difference between these is ownership. I&#39;m now considering the differences between RPM, a package from the systems family, and Helm charts, packages from the hierarchical family. I do this because charts are unique (as far as I can tell) because &lt;a href=&quot;https://docs.helm.sh/chart_template_guide/#subcharts-and-global-values&quot;&gt;you can configure them using their values.yaml file from a parent chart&lt;/a&gt;. This means that in some sense depending packages in helm can configure their depended on packages.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Contrast this with RPM. A Java app like &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;&amp;nbsp;installed &lt;a href=&quot;https://pkg.jenkins.io/redhat/&quot;&gt;via RPM&lt;/a&gt; would never presume to configure Java for you. Things like Java heap size are entirely up to the administrator. A central authority emerges in this model, where the sysadmin or &amp;lt;&lt;a href=&quot;https://saltstack.com/&quot;&gt;insert&lt;/a&gt; &lt;a href=&quot;https://www.ansible.com/&quot;&gt;favorite&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Infrastructure_as_Code&quot;&gt;infrastructure-as-code&lt;/a&gt; &lt;a href=&quot;https://puppet.com/&quot;&gt;tool&lt;/a&gt; &lt;a href=&quot;https://www.chef.io/&quot;&gt;here&lt;/a&gt;&amp;gt; tool is responsible for configuring the package and making it work.&lt;/div&gt;
&lt;h3&gt;
Which is Better?&lt;/h3&gt;
&lt;div&gt;
I think this boils down to a discussion around where the authority should be. Should packages be made to share resources owned by a central authority (the sysadmin), or should they be given their own sandbox, allowed to use what&#39;s in their box with no regard to the needs of other packages?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This has a direct corollary question to human communities and how communication takes place, &lt;a href=&quot;https://wingolog.org/archives/2015/11/09/embracing-conways-law&quot;&gt;as it must&lt;/a&gt;. Should developer teams coordinate, often centrally? Or, should we try to isolate developer teams so that they do not need to coordinate or communicate?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This question sounds harsh, but do and must ask and answer this question all the time. It is everywhere. This is particularly true in DevOps, which is my profession. Do we make two teams&#39; products share a virtual machine when we deploy their code, or do they get separate VMs? We usually choose the latter isolating them from each other. Do we make two teams&#39; products agree on what version of PostgreSQL to use, though they will use separate databases? Yes; our support contract only supports certain versions of this backing, depended-on service. Both teams depend on the database admins, and the database admins&#39;s service won&#39;t work with theirs unless certain constraints are met.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So: as a package manager designer, which one do we choose? Do we enforce some coordination between packages? If we do, all packages will agree on semantics (e.g., &amp;nbsp;package &quot;B&quot; will mean the same thing to all depending packages, because it will be the same version). All packages will need some central authority to configure them. If we don&#39;t, packages could be allowed to configure sub-packages, depending in turn on configuration given to them. Do we trust package authors to make the right configuration choices? They may be trustworthy, but will have no knowledge of other packages within the same installation. Will this cause problems?&amp;nbsp;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/7733867584267939348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2017/08/on-package-management-strategy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7733867584267939348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7733867584267939348'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2017/08/on-package-management-strategy.html' title='On Package Manager Architectures, Part I'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-8999802659901990610</id><published>2016-06-22T22:13:00.004-07:00</published><updated>2016-06-23T10:51:25.978-07:00</updated><title type='text'>Modeling Recursive Sum Types in C++11 Using boost::variant</title><content type='html'>It&#39;s been a while. But here&#39;s something cool.&lt;br /&gt;
&lt;br /&gt;
I used to &lt;b&gt;love&lt;/b&gt; pattern matching with sum types in OCaml in college. But I &lt;b&gt;also&lt;/b&gt;
love how useful and ubiquitous C++ is. So I wanted pattern matching
and sum types, but in C++. Well, people say boost::variant can be
used as a sum type. The library boost::variant is fairly ubiquitous,
well-maintained, and can even run on C++98, the older C++ standard. I
can see how discriminated unions can implement “flat” sum types,
but can it be used to implement &lt;b&gt;recursive&lt;/b&gt;
sum types?&lt;br /&gt;
&lt;br /&gt;
Well, I decided to try it. It turns out, with a bit of scaffolding
on my part, I was able to implement a recursive sum type. I tried to
model the quintessential recursive type, the natural number, which is
either zero or the successor to some other number. The following code shows the results of
my efforts.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// sum_type.cpp
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;boost/variant.hpp&amp;gt;
#include &amp;lt;memory&amp;gt;

struct zero {};
class successor;

typedef boost::variant&amp;lt;zero,successor&amp;gt; number;

class successor
{
private:
    std::unique_ptr&amp;lt;const number&amp;gt; num;
public:
    successor() = delete;
    successor(const number&amp;amp; n) : num(new number(n)) {}
    successor(const successor&amp;amp; s) : num(new number(s.n())) {}
    successor(successor&amp;amp;&amp;amp; s) : num(std::move(s.num)) {}

    const number&amp;amp; n() const {
        return *num;
    }
};

struct match_count : public boost::static_visitor&amp;lt;int&amp;gt;
{
    int operator ()(const zero&amp;amp; z) const
    {
        return 0;
    }
    int operator ()(const successor&amp;amp; s) const
    {
        // Do NOT use `return (*this)(s.n()) + 1`
        return boost::apply_visitor(*this, s.n()) + 1;
    }
};

number add(const number&amp;amp; a, const number&amp;amp; b)
{
    /*
     match a with
        0 =&amp;gt; b
        S n =&amp;gt; S add(n, b)
    */
    struct match_a : public boost::static_visitor&lt;number&gt;
    {
        const number b;
        match_a(const number&amp;amp; b) : b(b) {}
        number operator()(const zero&amp;amp; a) const
        {
            return b;
        }
        number operator()(const successor&amp;amp; a) const
        {
            return successor(add(a.n(), b));
        }
    };
    return  boost::apply_visitor(match_a(b), a);
}

int main() {
    number a = zero();
    number b = successor(a);
    number c = successor(b);
    number d = add(b,c);
    match_count mc;
    int c_count = boost::apply_visitor(mc, c);
    int b_count = boost::apply_visitor(mc, b);
    int a_count = boost::apply_visitor(mc, a);
    int added = boost::apply_visitor(mc, d);
    std::cout &amp;lt;&amp;lt; &quot;a is &quot; &amp;lt;&amp;lt; a_count &amp;lt;&amp;lt; std::endl;
    std::cout &amp;lt;&amp;lt; &quot;b is &quot; &amp;lt;&amp;lt; b_count &amp;lt;&amp;lt; std::endl;
    std::cout &amp;lt;&amp;lt; &quot;c is &quot; &amp;lt;&amp;lt; c_count &amp;lt;&amp;lt; std::endl;
    std::cout &amp;lt;&amp;lt; &quot;a + b is &quot; &amp;lt;&amp;lt; added &amp;lt;&amp;lt; std::endl;
}
&lt;/number&gt;&lt;/pre&gt;
&lt;br /&gt;
Output:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;[ djhaskin987@djhaskin987-S301LA:~ ]$ g++ -o sum_type -std=c++11 sum_type.cpp
[ djhaskin987@djhaskin987-S301LA:~ ]$ ./sum_type
a is 0
b is 1
c is 2
a + b is 3
&lt;/pre&gt;
How about that?&lt;br /&gt;
I modelled the type as a discriminated union between “zero” and
“successor”. Some interesting things I learned when I did this,
or at least some things to note:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;As long as you manage memory properly in the recursive cases, they work fine as part of the sum type using boost::variant.&lt;/li&gt;
&lt;li&gt;It’s okay to have a type with no members (e.g. &lt;tt&gt;struct zero {};&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;You can define anonymous classes inside function
definitions. Here, they aren’t anonymous, but experimentation will
show that you can (in C++11).&lt;/li&gt;
&lt;li&gt; You can call functions recursively when you define structs inside
those functions. That’s nice.&lt;/li&gt;
&lt;li&gt;When defining “matching” structs inside functions, try to match
variable names with class member names that they are used to
construct. This saves time later reasoning about what’s going on.&lt;/li&gt;
&lt;/ul&gt;
</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/8999802659901990610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2016/06/modeling-recursive-sum-types-in-c11.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/8999802659901990610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/8999802659901990610'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2016/06/modeling-recursive-sum-types-in-c11.html' title='Modeling Recursive Sum Types in C++11 Using boost::variant'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-5088087483720620146</id><published>2014-12-03T21:12:00.002-08:00</published><updated>2014-12-03T21:12:34.969-08:00</updated><title type='text'>svopt</title><content type='html'>&lt;div class=&quot;post-content&quot;&gt;
&lt;h2 class=&quot;title&quot;&gt;
&lt;/h2&gt;
&lt;div class=&quot;body-text&quot;&gt;
The optimization 
algorithm “vopt” applied to any optimization problem is simple. I now 
outline my own version, which I call “s-vopt” because it “swings” from 
one level of opt local search to another.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Convert your solution representation to a bit array.&lt;/li&gt;
&lt;li&gt;Go through each bit, flip it, and see if it improves the solution. 
If it does, keep the bit flipped and repeat until there are no more bits
 that can be flipped to reach a local maxima (assuming you’re maximizing
 a fitness function). You have now reached a local 1-opt maxima.&lt;/li&gt;
&lt;li&gt;Now flip each possible pair of bits, flip them, and see if the 
fitness rating improves. if it does, keep those bits flipped and go to 
step 2. If all the pairs have been tried without success continue to the
 next step.&lt;/li&gt;
&lt;li&gt;Continue in this fashing, first trying to flip all possible triples,
 then quadruples, then quintuples, etc. until you want to stop. At each,
 if an improved solution is found, keep it and go to step 2. if not, 
continue on the next step.&lt;/li&gt;
&lt;/ol&gt;
Happy Mountain Climbing!&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://media.tumblr.com/0ba2bb74755baaf5c7c88b09a96fb713/tumblr_inline_nfpcimYY2A1saws7v.png&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/5088087483720620146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2014/12/svopt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/5088087483720620146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/5088087483720620146'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2014/12/svopt.html' title='svopt'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-231900032135982669</id><published>2014-02-12T10:20:00.001-08:00</published><updated>2014-02-12T13:08:01.014-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Business"/><category scheme="http://www.blogger.com/atom/ns#" term="DevOps"/><category scheme="http://www.blogger.com/atom/ns#" term="IT"/><category scheme="http://www.blogger.com/atom/ns#" term="Technology"/><title type='text'>&quot;Brent&quot;: the Story of the Volunteer Warrior, and The Mayhem That Ensued</title><content type='html'>If
 you haven&#39;t read &lt;a href=&quot;http://www.amazon.com/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B00AZRBLHO/ref=sr_1_1?ie=UTF8&amp;amp;qid=1392229179&amp;amp;sr=8-1&amp;amp;keywords=the+phoenix+project&quot;&gt;The Phoenix Project&lt;/a&gt;, I gotta tell ya, it&#39;s a good book
 (even though there is some language in it, admittedly true to life in 
many IT organizations). In there is a story of an engineer called Brent.
 Brent is crucial for most IT operations of any kind. Every thing he 
knows is in only his head, and documented nowhere. If anything is to get
 done, Brent needs to be involved.&lt;br /&gt;
&lt;br /&gt;
A real time-bomb situation.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.mariowiki.com/images/thumb/6/63/BobombNSMBU.png/200px-BobombNSMBU.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.mariowiki.com/images/thumb/6/63/BobombNSMBU.png/200px-BobombNSMBU.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The book goes on to talk about how to diffuse this time bomb, but it doesn&#39;t talk about how to prevent it in the first place.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
The Perfect Storm for Brent&lt;/h2&gt;
&lt;br /&gt;
This happened because of the 
&quot;Volunteer Viscous Cycle&quot;. It happens when the dispatching of problems 
to engineers to fix them happens on a volunteer basis.&lt;br /&gt;
&lt;br /&gt;
The following diagram shows, in essence, what happens in the volunteer workflow:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeFZWxk0B24J0wwdHqJorDRtLPfFHD-f3Tire2U5blaYIkMZRPBK372xF2Hiqk3mVPjBz3_vrXw1TTH9xYQT-_z4vM50kO7ZRRc_MCFC5KULw77irH4QzO__uqd-ARM6P1Aylf9Id5iSuQ/s1600/Brent.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeFZWxk0B24J0wwdHqJorDRtLPfFHD-f3Tire2U5blaYIkMZRPBK372xF2Hiqk3mVPjBz3_vrXw1TTH9xYQT-_z4vM50kO7ZRRc_MCFC5KULw77irH4QzO__uqd-ARM6P1Aylf9Id5iSuQ/s1600/Brent.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
This is &lt;i&gt;exactly&lt;/i&gt;
 what creates a Brent: an uncontrolled, volunteer-based dispatch system 
when problems arise. A team of engineers hesitant to jump in and help, 
and one volunteer, constitues a perfect storm for new Brents to form.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
The New Problem&lt;/h3&gt;
&lt;br /&gt;
&lt;br /&gt;
When
 a new problem arises --&amp;nbsp; a bug, a ticket, or an issue, depending on 
your issue tracking system -- engineers on a team often hesitate to take
 it, given that they can choose what problems to take and what to fix. 
They are not hesitant to take the issue because they are lazy or dumb. 
They are most often well-educated, highly-trained, seasoned engineers; 
however, new problems, never seen before, still daunt these engineers. 
Any engineer who takes it will make lots of mistakes, become frustrated,
 and spend lots of time fixing it. Further, they could use the same time
 to fix 3 problems that they know how to fix. So, they wait and see if 
someone else will volunteer to take this particular problem.&lt;br /&gt;
&lt;br /&gt;
Enter
 Brent, a guy who just wants to get stuff done. He may be highly 
educated, or he may be just out of high school, but he has drive. He&#39;ll 
volunteer for anything, either because he&#39;s just trying to be helpful, 
or because he&#39;s trying to show that he is valuable, or simply because no
 one else will take the ticket. He&#39;s a first-rate volunteer, a real 
go-getter. And he&#39;s about to become a dumping ground for all sorts of 
problems.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Brent sees that others do not feel
 comfortable hacking at a problem and helpfully, proudly, or even 
meekly, volunteers. It takes him a while, but he eventually resolves the
 issue and everyone&#39;s happy.&lt;br /&gt;
&lt;br /&gt;
Brent
 starts taking on so many of these new issues that people just assume 
it&#39;s &quot;Brent&#39;s job&quot; or &quot;Brent&#39;s niche&quot; to take on new or unusual tasks, 
and so come to expect them picking up the slack.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
The Returning Bug (Uh-Oh)&lt;/h3&gt;
&lt;h3&gt;
&amp;nbsp;&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://static1.fjcdn.com/comments/That+was+the+longest+++gif+I+ve+ever+seen+but+_ed02ba77425b32e71cbe491199ce4521.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://static1.fjcdn.com/comments/That+was+the+longest+++gif+I+ve+ever+seen+but+_ed02ba77425b32e71cbe491199ce4521.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Brent
 eventually takes on enough issues that a few of them reappear, or new 
issues appear which are related to older ones. This time, something in 
the server environment changed, which breaks a service that Brent has 
previously serviced. Everyone instantly sees this server is broken and 
remembers how hard Brent worked on this problem last time. They think 
that he&#39;ll be able to do it faster than themselves, and so it is 
assigned to him. He may even volunteer for to take the issue, trying to 
be helpful. Brent fixes it for the team. He learns even more about the 
server than he knew from the last time he fixed it. The problem is, 
others on his team know even less, because they stopped worrying about 
the server once the issue was given to Brent.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
The Silo Effect&lt;/h3&gt;
&lt;h3&gt;
&amp;nbsp;&lt;/h3&gt;
A
 long time passes with this process in place. It is now too difficult 
for all of Brent&#39;s knowledge to be documented. There&#39;s simply too much 
to write it all down, and quite frankly, too many fires that Brent needs
 to fight. When problems arise that have to do with &quot;Brent&quot; servers, the
 only one that can fix them is Brent. He is now considered a &quot;crucial 
resource&quot;. It is simply a waste of Brent&#39;s valuable time to document 
issues already fixed, when there are so many &lt;i&gt;current&lt;/i&gt; issues that only he can fix. There simply isn&#39;t time. &lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Diffusion&lt;/h2&gt;
&lt;i&gt;The Phoenix Project&lt;/i&gt; goes into some good detail about how to diffuse this situation. As a recap:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Limit Brent&#39;s work-in-process by using the &lt;a href=&quot;http://www.kanbanblog.com/explained/&quot;&gt;kanban process&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Get engineers shadowing Brent.&lt;/li&gt;
&lt;li&gt;Disallow Brent the keyboard. His shadows must do all the work.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Prevention&lt;/h2&gt;
In order to diffuse Brent, you must put mulitple 
shadow engineers on him, lest he quit and you end up with &quot;just another 
Brent&quot;. &lt;b&gt;More than one engineer at a time must know how fix any given problem in their space of responsibility&lt;/b&gt;, and hopefully in more than their region of responsibility.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUBfdkRYXw8t-JP7y6suIyN_A0gy9W_220DBr3zf6FQNiCPiPWxzzqpMtSlWE4t-q24WXdT8zUsU9eJnyLP-cmkYT44YvQlLCanRnVyeuYt-3xQ-dCfzOBLrZcv1DBzMDAnB5ncjI5m4xd/s1600/TertiaryRedundance.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUBfdkRYXw8t-JP7y6suIyN_A0gy9W_220DBr3zf6FQNiCPiPWxzzqpMtSlWE4t-q24WXdT8zUsU9eJnyLP-cmkYT44YvQlLCanRnVyeuYt-3xQ-dCfzOBLrZcv1DBzMDAnB5ncjI5m4xd/s1600/TertiaryRedundance.png&quot; height=&quot;222&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
A great way to ensure this from the start to institute round-robin assignment of issues to members of the team. Rules:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Issues are assigned to members of a team in a round-robin fashion. This way everyone knows about everything.&lt;/li&gt;
&lt;li&gt;If an engineer needs help on an issue from another engineer, he may 
request that the engineer document the process and then send him a link 
to the wiki page, but the only the engineer assigned the ticket, issue, 
task, or subtask must actually do the work. This way, every thing 
currently worked on is currently documented. &lt;/li&gt;
&lt;/ol&gt;
Rule 2 above is especially useful. If the wiki page is unclear, 
the author must clarify the wiki page so the engineer can do the work.&amp;nbsp; 
If a particular engineer is called on to write multiple wiki pages, it 
is probably a sign that he has been a &quot;Brent&quot; in the past and so rule 2 
naturally protects against such volunteer warriors. If everyone knows 
how to fix a particular issue, then the idea is that if a particular 
engineer needs help on that issue, he can ask the team, or otherwise a 
more or less random person. The main point is that the author or authors
 of the wiki page are asked to write it. This principle guards against 
volunteer warriors. &lt;br /&gt;
&lt;br /&gt;
Rule 1 may seem inefficient, since
 some engineers naturally find it easier to solve some problems than 
others. It is not meant to be efficient; rather, it endows &lt;i&gt;resilience&lt;/i&gt;
 to a team. You&#39;ll never find an IT team with efficiency problems, but I
 have yet to find one without resiliency problems. Lots of IT 
professionals will brag about how many VMs they can manage, or how fast 
they can fix a problem, but those same IT techs will tell you horror 
stories about when something went down and Brent was on vacation. IT 
organizations who follow Rule 1 will find that the tradeoff between 
efficiency and resiliency is worth it. Bugs will be fixed slower, but 
they will always be fixable, come rain, shine, or even (gasp!) a sick 
Brent.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;EDIT&lt;/b&gt;: An earlier version of this article used &quot;Brett&quot; instead of &quot;Brent&quot;. The character in The Phoenix Project is &quot;Brent&quot;, so the name &quot;Brett&quot; in this article was changed to match the character, consistent with what I was trying to do on the first draft. </content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/231900032135982669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2014/02/brett-story-of-volunteer-warrior-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/231900032135982669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/231900032135982669'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2014/02/brett-story-of-volunteer-warrior-and.html' title='&quot;Brent&quot;: the Story of the Volunteer Warrior, and The Mayhem That Ensued'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeFZWxk0B24J0wwdHqJorDRtLPfFHD-f3Tire2U5blaYIkMZRPBK372xF2Hiqk3mVPjBz3_vrXw1TTH9xYQT-_z4vM50kO7ZRRc_MCFC5KULw77irH4QzO__uqd-ARM6P1Aylf9Id5iSuQ/s72-c/Brent.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-2839343593366996876</id><published>2014-01-16T18:59:00.001-08:00</published><updated>2014-01-16T18:59:53.511-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fluxbox"/><category scheme="http://www.blogger.com/atom/ns#" term="howto"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="ratpoison"/><category scheme="http://www.blogger.com/atom/ns#" term="window manager"/><title type='text'>ratpoison and xdotool: How to Move the Mouse by Using the Keyboard in Linux</title><content type='html'>We interrupt this blog for an important announcement: With &lt;a href=&quot;http://www.nongnu.org/ratpoison/&quot;&gt;ratpoison&lt;/a&gt;, you can use the mouse using keyboard bindings!&lt;br /&gt;
&lt;br /&gt;
For those of you who don&#39;t know what ratpoison is, it&#39;s a &lt;a href=&quot;https://wiki.archlinux.org/index.php/Window_Manager&quot;&gt;window manager &lt;/a&gt;for linux, like &lt;a href=&quot;http://fluxbox.org/&quot;&gt;fluxbox&lt;/a&gt;, &lt;a href=&quot;http://www.gnome.org/&quot;&gt;GNOME&lt;/a&gt;, or &lt;a href=&quot;http://www.kde.org/&quot;&gt;KDE&lt;/a&gt;. It&#39;s designed to be able to work without a mouse (hence the name). Using ratpoison, I have found a way to use the pointer without actually using the mouse.&lt;br /&gt;
&lt;br /&gt;
Here is my &lt;code&gt;.ratpoisonrc&lt;/code&gt; file:&lt;br /&gt;
&lt;pre&gt;startup_message off
set font Mono-10
set bargravity nw
set bgcolor cyan
exec rpws -i
exec /usr/bin/rpws init 4 -k
source .ratpoisonkeys
source .ratpoisonmouse
set winname class

set border 0
&lt;/pre&gt;
&lt;br /&gt;
And here is my &lt;code&gt;.ratpoisonmouse&lt;/code&gt; file:&lt;br /&gt;
&lt;pre&gt;bind C-j ratclick 1
bind C-k ratclick 2
bind C-l ratclick 3
definekey top M-j ratrelwarp 0 16
definekey top M-k ratrelwarp 0 -16
definekey top M-h ratrelwarp -16 0
definekey top M-l ratrelwarp 16 0
definekey top M-y ratrelwarp -16 -16
definekey top M-u ratrelwarp 16 -16
definekey top M-b ratrelwarp -16 16
definekey top M-n ratrelwarp 16 16

definekey top M-J ratrelwarp 0 256
definekey top M-K ratrelwarp 0 -256
definekey top M-H ratrelwarp -256 0
definekey top M-L ratrelwarp 256 0
definekey top M-Y ratrelwarp -256 -256
definekey top M-U ratrelwarp 256 -256
definekey top M-B ratrelwarp -256 256
definekey top M-N ratrelwarp 256 256

definekey top F10 ratclick 1
definekey top F11 ratclick 2
definekey top F12 ratclick 3
definekey top M-i rathold down 1
definekey top M-o rathold down 2
definekey top M-p rathold down 3
definekey top M-I rathold up 1
definekey top M-O rathold up 2
definekey top M-P rathold up 3
&lt;/pre&gt;
&lt;br /&gt;
The entries in the above file mean that if I type ALT+H,J,K, or L, I can move the mouse left, down, up or right. F10 clicks on stuff, and F12 right-clicks on stuff. The rest can be extrapolated, I think, by looking at the .&lt;code&gt;ratpoisonmouse&lt;/code&gt; file above.&lt;br /&gt;
&lt;br /&gt;
Don&#39;t wanna &lt;a href=&quot;https://wiki.archlinux.org/index.php/Ratpoison&quot;&gt;switch to ratpoison&lt;/a&gt;? You can do the same thing in any other linux window manager using &lt;a href=&quot;http://www.semicomplete.com/projects/xdotool/xdotool.xhtml&quot;&gt;xdotool&lt;/a&gt;. It&#39;s a commandline program that lets you move the mouse around, among other things. By binding keystrokes to different xdotool commands, you can get the mouse to move and click.&lt;br /&gt;
&lt;br /&gt;
For example, here is what could be an excerpt from &lt;code&gt;.fluxbox/keys&lt;/code&gt;, the fluxbox keybindings file to do move the mouse up, down, left and right as explained above, plus click the mouse:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;Mod1 j :Exec &quot;xdotool mousemove_relative -- 0 16&quot;
Mod1 k :Exec &quot;xdotool mousemove_relative -- 0 -16&quot;
Mod1 h :Exec &quot;xdotool mousemove_relative -- -16 0&quot;
Mod1 l :Exec &quot;xdotool mousemove_relative -- 16 0&quot;
F10 :Exec &quot;xdotool click 1&quot;
F11 :Exec &quot;xdotool click 2&quot;
F12 :Exec &quot;xdotool click 3&quot;
&lt;/pre&gt;
&lt;br /&gt;
Cool, huh?</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/2839343593366996876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2014/01/ratpoison-and-xdotool-how-to-move-mouse.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/2839343593366996876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/2839343593366996876'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2014/01/ratpoison-and-xdotool-how-to-move-mouse.html' title='ratpoison and xdotool: How to Move the Mouse by Using the Keyboard in Linux'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-755172744296159405</id><published>2014-01-16T17:50:00.001-08:00</published><updated>2014-01-16T18:38:50.798-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nsa"/><category scheme="http://www.blogger.com/atom/ns#" term="privacy"/><category scheme="http://www.blogger.com/atom/ns#" term="user data"/><title type='text'>How to Comply With the NSA While Maintaining Privacy For Your Users</title><content type='html'>&lt;a href=&quot;http://mashable.com/2013/08/09/silent-circle-lavabit-shut-down-to-avoid-nsa-snooping/&quot;&gt;Silent Circle and Lavabit closed their doors&lt;/a&gt; because they didn&#39;t wish to give their user data to the NSA. This article describes how a web service can fairly easily store user data so that nobody--not even 
the hosting web service--could access private user data, except the user to whom the 
rightfully belongs. This can even be done while complying to the NSA. You can store metadata (the kind of data the NSA cares about) about a user unencrypted while still encrypting the user&#39;s address and telephone number fairly easily.&lt;br /&gt;
&lt;h3&gt;
&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;
Storing Private Data Securely &lt;/h3&gt;
&lt;br /&gt;
First, let&#39;s go back in time to
 the &lt;a href=&quot;http://arstechnica.com/tech-policy/2011/06/sony-hacked-yet-again-plaintext-passwords-posted/&quot;&gt;Sony hack&lt;/a&gt;. This was especially embarassing to Sony because they 
stored all their passwords in plain text. For those technically normal 
people out there, &lt;a href=&quot;http://en.wikipedia.org/wiki/Cryptographic_hash_function&quot;&gt;there is a way to create data based on a password called a &lt;i&gt;hash&lt;/i&gt;&lt;/a&gt;,
 store that data, and then use that data later to check whether a user 
entered their password correctly or not by making another hash and check
 whether it matches the stored hash. It is fairly easy to store password hashes instead of the password itself, and it is far more secure to do so.&lt;br /&gt;
&lt;br /&gt;
Admittedley, it is a little more complicated than that. In order to thwart &lt;a href=&quot;http://netsecurity.about.com/od/hackertools/a/Rainbow-Tables.htm&quot;&gt;rainbow tables&lt;/a&gt;, web site owners need to store a &quot;&lt;a href=&quot;https://crackstation.net/hashing-security.htm&quot;&gt;salt&lt;/a&gt;&quot; (a large random number) for each user and then create a hash based on the salt and the password together. The bottom line, however, is that it is not that difficult to store a password securely.&lt;br /&gt;
&lt;br /&gt;
It is not as easy (if what is explained above can be called easy) to store credit card information and addresses securely, and it is likely that the majority of web site owners don&#39;t even try to do so.&lt;br /&gt;
&lt;br /&gt;
So how do you, as a web site owner, keep your users&#39; personal information personal?&lt;br /&gt;
&lt;br /&gt;
Like this: &lt;a href=&quot;http://en.wikipedia.org/wiki/Elliptic_curve_cryptography&quot;&gt;Elliptic Curve Cryptography&lt;/a&gt;.
 Briefly, ECC is a public/private key scheme, meaning you use one &quot;key&quot; 
(bit of data) to encrypt information and one to decrypt information. Since you don&#39;t 
care who encrypts your data as long as you can decrypt it, you share the
 &quot;encrypt&quot; key with everyone while keeping the &quot;decrypt&quot; key private, 
which is where the &quot;public/private&quot; part of the name comes from.&lt;br /&gt;
&lt;br /&gt;
The cool thing is that ECC allows you to encrypt data with very small keys. 
For example, normally web site traffic using the &#39;https://&#39; prefix use 
keys which are between 1024 bytes (characters) and 4096 bytes. Compare 
that to this string of characters, which is the ECC public key 
corresponding to one of my (old) passwords:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;!Dw3K-efjB6S1A%a[Qc4jp?XOxC[XnY+6;@Zfc)ba,7^7O#6Oi(]^Q@@wSkg6h)M(]XX6?6ptt
&lt;/pre&gt;
&lt;br /&gt;
The
 above string of characters is longer than a sentence, perhaps, but 
nowhere near the 1024 character essay. And the private key is simply as 
long as...say... a password. Let me state that again:&lt;i&gt; the actual data 
used to decrypt user info under the ECC scheme IS that user&#39;s password.&lt;/i&gt; It now is possible, then, for a user to decrypt their data by typing in their password upon login to the web site. Further, since it is possible for a web site owner to not store a user&#39;s password (only its hash), &lt;i&gt;not even the web site owner can decrypt private user data. &lt;/i&gt;The owner could then keep valuable meta data, such as log in and link-clicking history, while keeping data about the user which is doing the clicking private.&lt;br /&gt;
&lt;br /&gt;
Here is what to do as a website owner to store user data securely.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Store the user&#39;s salt.&lt;/li&gt;
&lt;li&gt;Store
 the hash of the user&#39;s password+salt. This allows you to securely check
 to see whether a user entered the right password on login&lt;/li&gt;
&lt;li&gt;Store the user&#39;s username in plain text. While unfortunate, you need to store the username in plain text so that you can look up that user&#39;s data in the database. It is then incumbent on the user to use a private username, say &quot;superSquirrel&quot;, instead of &quot;Daniel.Haskin&quot;. &lt;/li&gt;
&lt;li&gt;Upon registration of a user, generate and store that user&#39;s public key based on the the password they provide. (Don&#39;t worry; it is usually intractably difficult to get a user&#39;s password based on their public key.)&lt;/li&gt;
&lt;li&gt;Use that public key to encrypt the rest of the user&#39;s data housed within the database.&lt;/li&gt;
&lt;li&gt;When a user logs in to the web site:&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;The web site uses the username to look up the database entry.&lt;/li&gt;
&lt;li&gt;The password is verified using the salt and hash.&lt;/li&gt;
&lt;li&gt;The password is used to decrypt the user data.&lt;/li&gt;
&lt;li&gt;The unencrypted user data can then be used while the user is logged in, but it is never recorded anywhere by the web site.&lt;/li&gt;
&lt;li&gt;On log out (or the closing of the user session), the data is again encrypted and stored in the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
If a hacker should hack into a web service which implements the above, the hacker cannot access anything of value (at least, anything of value to a thief). Each user entry is secured separately, so that even if the hacker had enough computing power to crack an ECC key (no mean feat), it would only yield one user entry per cracked key. There would simply not be enough time or resources to crack the entire database, even if the cracker were the federal government.&lt;br /&gt;
&lt;br /&gt;
This plan would allow any web service using it to happily comply with the NSA and give them all the information about all the web service&#39;s users. This is because personal user data would be encrypted with a key that the web service doesn&#39;t have --- the user password. The web service would still store metadata unencrypted and then link it with the encrypted user data. That way, web service could still use the metadata for targeted marketing and data mining. It also means the NSA can then analyze the metadata. This gives them enough information to fight terrorism while also guaranteeing the privacy of individuals. In our example, they they don&#39;t know who user &quot;#1acd3fr3&quot; is; however, if their software flags that user as a terrorist, they can get a legal warrant asking a judge if they can go after the information for that username based on other means of investigation. But even if the NSA asked a web service owner who a particular user was, the owner would not be able to tell them, because they wouldn&#39;t have access to that information. Thus, the NSA can still do their jobs, and the web service can still use customer data to make more money, but sensitive user data can still be protected from hackers and &quot;bad apples&quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Tools of the Trade&lt;/h3&gt;
&lt;br /&gt;
Any database software vendor, such as &lt;a href=&quot;http://www.percona.com/&quot;&gt;Percona&lt;/a&gt; or &lt;a href=&quot;http://www.oracle.com/index.html&quot;&gt;Oracle&lt;/a&gt;, can get you the underlying database software needed. As for the encryption itself, a free and open-source implementation of ECC that I&#39;ve come to know and love is called &lt;a href=&quot;http://point-at-infinity.org/seccure/&quot;&gt;seccure&lt;/a&gt;. Some quick scripting to complete the algorithm that I have herein outlined should get any one seriously committed to user privacy well on their way to protecting their users&#39; private data.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/755172744296159405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2014/01/how-to-comply-with-nsa-while.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/755172744296159405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/755172744296159405'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2014/01/how-to-comply-with-nsa-while.html' title='How to Comply With the NSA While Maintaining Privacy For Your Users'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-8215857107770258592</id><published>2013-12-30T06:50:00.002-08:00</published><updated>2013-12-30T12:45:31.810-08:00</updated><title type='text'>Dragon NaturallySpeaking, Vimperator, and Emacs</title><content type='html'>My
 wife got me Dragon NaturallySpeaking for Christmas. It&#39;s been fun 
learning how to use it, but it&#39;s been frustrating learning how to browse
 the Internet with it. I ended up saying a lot of hotkeys while working 
with Firefox, such as &quot;press ctrl+k&quot; and &quot;press ctrl+pgdn&quot;.&lt;br /&gt;
&lt;br /&gt;
Then I 
discovered &lt;a href=&quot;http://vocola.net/v2/&quot;&gt;Vocola&lt;/a&gt;, which allows you to define your own custom voice 
commands. That, together with &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/vimperator/&quot;&gt;Vimperator&lt;/a&gt;, which I have already been 
using, it is now a breeze to use Dragon to browse.&lt;br /&gt;
&lt;br /&gt;
I just installed Vocola according to the directions found &lt;a href=&quot;http://vocola.net/v2/InstallVocola.asp&quot;&gt;here.&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Here is my &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;.vimperatorrc&lt;/span&gt; file:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;set hintchars=&#39;0123456789&#39;
inoremap &amp;lt;C-a&amp;gt; &amp;lt;Ins&amp;gt;&amp;lt;C-a&amp;gt;&amp;lt;Ins&amp;gt;
map J gT
map K gt
highlight Hint font-size:200%;color:white;background-color:red;padding:2px;
&lt;/pre&gt;
&lt;br /&gt;
Simply
 put this file in your home directory. If you are using a Windows 
operating system, this is something like c:\Users\djhaskin987. &lt;br /&gt;
&lt;br /&gt;
Then,
 with Vocola installed, use Dragon NaturallySpeaking to open Firefox, 
and say &quot;edit voice commands&quot;, and paste the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt; # Voice commands for firefox
visit &amp;lt;_anything&amp;gt; = {Esc}&quot;:open $1&quot;;
close tab = {Esc}d;
open tab &amp;lt;_anything&amp;gt; = {Esc}&quot;:tabopen $1&quot;;
follow &amp;lt;_anything&amp;gt; = {Esc} f $1;
follow tab &amp;lt;_anything&amp;gt; = {Esc} F $1;
next doc = {Esc} J;
previous doc = {Esc} K;
back = {Esc} H ;
&lt;/pre&gt;
&lt;br /&gt;
Viola! Easy browsing by speech. Just say &quot;follow &lt;name link=&quot;&quot; of=&quot;&quot;&gt;&quot;,
 or just &quot;follow&quot; and then say the number that pops up next to the link.
 To open a webpage, just say &quot;visit&quot; followed by the address. Vimperator 
will give you a menu of options. A couple of &quot;press tab&quot; and &quot;press enter&quot; commands later 
and you&#39;re in business.&lt;br /&gt;&lt;br /&gt;I also plan to use Vocola and Dragon 
NaturallySpeaking to improve my programming by defining some voice 
commands for Emacs, &lt;a href=&quot;http://ergoemacs.org/emacs/using_voice_to_code.html&quot;&gt;sort of like Tavis Rudd&lt;/a&gt;, only Vocola is way 
easier to define voice commands with than Python.&lt;br /&gt;&lt;br /&gt;Here is my Vocola file so far for Emacs:&lt;br /&gt;&lt;br /&gt;
&lt;/name&gt;&lt;br /&gt;
&lt;pre&gt;# Voice commands for emacs
&amp;lt;number&amp;gt; := 1..99;
open file = {Ctrl+x}{Ctrl+f};
boom = {Enter};
undo = {Ctrl+Shift+_};
die = {Alt+Backspace};
back = {Backspace};
whack = \;
um = {Alt+b};
curly = &quot;{&quot;;
close curly = &quot;}&quot;;
paren = &quot;(&quot;;
all in = &quot;)&quot;;
the &amp;lt;_anything&amp;gt; = $1;
start = {Ctrl+a};
end = {Ctrl+e};
camelize &amp;lt;_anything&amp;gt; = {Alt+x} camelize {Enter} $1 {Enter};
left = {Ctrl+b};
&amp;lt;number&amp;gt; up = {Ctrl+u} $1 {Ctrl+p};
&amp;lt;number&amp;gt; down = {Ctrl+u} $1 {Ctrl+n};
&amp;lt;number&amp;gt; left = {Ctrl+u} $1 {Ctrl+b};
right = {Ctrl+f};
up = {Ctrl+p};
down = {Ctrl+n};
go = {Alt+f};
scroll down = {Ctrl+v};
scroll up = {Ctrl+v};
cut = {Ctrl+k};
yank = {Ctrl+y};
nay = {Alt+y};&amp;nbsp; &lt;/pre&gt;
&lt;br /&gt;
The function &quot;camelize&quot; is an emacs lisp interactive function which takes a phrase like &quot;the grand old duke of york&quot; and turns it into &quot;theGrandOldDukeOfYork&quot;, kind of like &lt;a href=&quot;http://www.emacswiki.org/emacs/CamelCase&quot;&gt;what is found in the emacs wiki&lt;/a&gt;, but changing from space separated instead of underscore separated, and making the function interactive as well. &lt;br /&gt;
&lt;br /&gt;
I hope to also use Emacs templating like Tavis Rudd does in his video&amp;nbsp; to make functions and classes by speech easier in Emacs.&lt;br /&gt;
&lt;br /&gt;
EDIT: I&#39;m putting my vocola files for easy browsing and programming by voice in a &lt;a href=&quot;https://github.com/djhaskin987/programmers-vocola&quot;&gt;git repository&lt;/a&gt;. Pull requests wecome! </content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/8215857107770258592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/dragon-naturallyspeaking-vimperator-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/8215857107770258592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/8215857107770258592'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/dragon-naturallyspeaking-vimperator-and.html' title='Dragon NaturallySpeaking, Vimperator, and Emacs'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-3068727361618764617</id><published>2013-12-19T09:25:00.001-08:00</published><updated>2013-12-19T09:33:58.265-08:00</updated><title type='text'>Mancakes</title><content type='html'>What do you want? I dabble.&lt;br /&gt;
&lt;br /&gt;
I have this amazing pancake recipe I made up.&lt;br /&gt;
&lt;br /&gt;
I take this from the original &quot;German Pancake&quot; recipe my wife found, but that was baked in the oven. This is in a pan.&lt;br /&gt;
&lt;br /&gt;
It&#39;s called a Mancake rather than a pancake for the following reasons:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;It has tons of eggs (protein) in it&lt;/li&gt;
&lt;li&gt;It is dead simple -- only requires a 1/2 cup size measuring cup and a teaspoon. (For those of you who subscribe to the metric system, a 1/2 cup is 120ml and a teaspoon is 5ml).&lt;/li&gt;
&lt;li&gt;The recipe serves one (1) hungry person (likely, therefore, a man).&lt;/li&gt;
&lt;/ol&gt;
Here it is:&lt;br /&gt;
&lt;br /&gt;
1/2 cup milk&lt;br /&gt;
1/2 cup (whole wheat pastry) flour&lt;br /&gt;
2 eggs&lt;br /&gt;
4 teaspoons (olive) oil (20ml, or 1/12 cup)&lt;br /&gt;
1 teaspoon baking powder, or 1 teaspoon baking soda and 2 teaspoons (apple cider) vinegar&lt;br /&gt;
1 pinch salt&lt;br /&gt;
&lt;br /&gt;
Combine ingredients in a slightly-larger-than-normal bowl using an ordinary fork. Pre-heat your (electric) stove to a &quot;6&quot; (just past medium heat) while your skillet is on that stove. Pour 1/2 cup of batter onto the skillet. When there are a bunch of bubbles on the mancake, place your spatula under the right half of the large mancake and flip (or, for lefties, the left half of the mancake). Wait one &amp;nbsp;minute, then take out of the pan and repeat. Makes 3 mancakes. Serves one. Enjoy.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/3068727361618764617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/mancakes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/3068727361618764617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/3068727361618764617'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/mancakes.html' title='Mancakes'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-112179547537711794</id><published>2013-12-16T09:56:00.000-08:00</published><updated>2013-12-16T10:03:24.226-08:00</updated><title type='text'>Moving On</title><content type='html'>So I could put another post on here about the genetic algorithm, but everything I wanted to say on the subject has been said about that particular algorithm.&lt;br /&gt;
&lt;br /&gt;
Rest assured, I have many more ideas about optimization algorithms. But let me tell you -- it&#39;s getting frustrating. A lot of my ideas about new algorithms for optimization include this &lt;a href=&quot;http://djhaskin987.blogspot.com/2013/07/the-rankedset-optimizations-best-friend.html&quot;&gt;RankedSet&lt;/a&gt; idea... and it doesn&#39;t exist in standard libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://stackoverflow.com/users/232707/michal-marczyk&quot;&gt;Michał Marczyk&lt;/a&gt; &lt;a href=&quot;http://stackoverflow.com/a/18927577/850326&quot;&gt;made one&lt;/a&gt; for Clojure called &lt;a href=&quot;https://github.com/michalmarczyk/avl.clj&quot;&gt; avl.clj&lt;/a&gt; (great job, Michał!), and &lt;a href=&quot;http://en.wikipedia.org/wiki/AVL_tree&quot;&gt;AVL tree&lt;/a&gt; implementation of what I call the RankedSet, but the genetic algorithm as below described (and other algorithms bouncing around in my head) need faster insertions/deletions and virtually no lookup. That is precisely what &lt;a href=&quot;http://en.wikipedia.org/wiki/Red_black_trees&quot;&gt;red-black trees&lt;/a&gt; are better at over AVL trees.&amp;nbsp; I need a red-black tree based implementation.&lt;br /&gt;
&lt;br /&gt;
So I decided to learn how to make one.&lt;br /&gt;
&lt;br /&gt;
I am currently going through &lt;a href=&quot;http://www.amazon.com/Purely-Functional-Structures-Chris-Okasaki/dp/0521631246/ref=tmm_hrd_title_0&quot;&gt;Chris Oksasaki&#39;s &quot;Purely Functional Data Structures&quot;&lt;/a&gt;. (Even just reading the first chapter, you can tell &lt;a href=&quot;http://en.wikipedia.org/wiki/Rich_Hickey&quot;&gt;Rich Hickey&lt;/a&gt; idolizes the guy, and for good reason.) For those who don&#39;t know, this is a seminal work on how to design your own rock-star data structures. A quote from the first chapter:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;br /&gt;
Rather than attempting to catalog efficient data structures for every purpose (a hopeless task!), we instead concentrate on a handful of general techniques for designing efficient functional data structures...Once you understand the techniques involved, you can easily adapt existing data structures to your particular needs, or even design new data structures from scratch. (p. 4) &lt;/blockquote&gt;
I am even learning OCaml so that I can go through it better (most of the examples in his book are in standard ML, which is to OCaml as C is to C++, as far as I can tell). &lt;br /&gt;
&lt;br /&gt;
Hopefully at some point into it I&#39;ll be able to make a RankedSet, share the implementation, and keep writing about awesome algorithms.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/112179547537711794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/moving-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/112179547537711794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/112179547537711794'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/12/moving-on.html' title='Moving On'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4803952895931388668</id><published>2013-09-03T20:42:00.003-07:00</published><updated>2013-09-04T17:16:01.316-07:00</updated><title type='text'>The New Genetic Aglorithm: What Makes It New</title><content type='html'>
In
 the last post of my &#39;New Genetic Algorithm&#39; posts, I talked about the
RankedSet, which is the backbone of the algorithm, and what makes the
algorithm &lt;i&gt;fast&lt;/i&gt;. In this post, I&#39;ll talk about what makes the algorithm &lt;i&gt;easy to use&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;
Keeping it Simple&lt;/h1&gt;
Nobody likes using a tool with a bunch of dials
and switches on it. Would you rather use a drill with five dials on it with
 labels on those dials that look like they have made-up words on it? And
 you&#39;re thinking, &quot;I just want to drill a hole!&quot;
&lt;br /&gt;

&lt;br /&gt;
&lt;br /&gt;
You are not alone. Most people, when faced with using
something like a drill, or washing machine, or algorithm, would much
rather use an &#39;on&#39; switch than anything else.
&lt;br /&gt;

&lt;br /&gt;
The thing is, most genetic algorithms that I&#39;ve come across have &lt;i&gt;five&lt;/i&gt; dials on it, which all need to be set properly in order for the algorithm to work:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;The fitness function&lt;/li&gt;
&lt;li&gt;When to stop&lt;/li&gt;
&lt;li&gt;What the kill-off rate will be&lt;/li&gt;
&lt;li&gt;What the mutation rate will be&lt;/li&gt;
&lt;li&gt;The size of the initial population &lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;

&lt;br /&gt;
I believe that the genetic algorithm is only used,
either in heavy industry, or academia, precisely because it has five dials
and switches. One almost needs an algorithm to solve the problem of how to set these &quot;dials&quot;!&lt;br /&gt;
&lt;br /&gt;So, a major goal of this new genetic algorithm is to take
the algorithm to the masses. It asks the question: &quot;What would a normal person care about?&quot;&lt;br /&gt;
&lt;br /&gt;A normal person would care about the first two things in the above list:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;the fitness function and&amp;nbsp;&lt;/li&gt;
&lt;li&gt;when to stop.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;

&lt;br /&gt;
A &quot;fitness function&quot; is a set of instructions given to the
algorithm to score the solutions it finds. To stick with our previous
post&#39;s example, the &quot;solutions&quot; represent which strategy to employ in
getting food for my family on the way home from work: Do I get takeout?
Do I get fast food? Do I go home and cook something? etc. It&#39;s easy to
tell an algorithm &quot;I want food quickly, and I&#39;m willing to spend a
little to get good food, too.&quot; A statement like this is, in essence, the
 &quot;fitness function&quot;. With this fitness function, the genetic algorithm
would score &#39;getting takeout&#39; high, and &#39;cooking at home&#39; low.  The
fitness function is both easy to understand and essential for the
algorithm to work, we&#39;ll probably keep this as an input to the algorithm
 as it is.&lt;br /&gt;
&lt;br /&gt;The question of &quot;when to stop&quot; is also
relatively straight forward to answer for the user of the algorithm, but
 hard for the algorithm itself to answer. Something like &quot;stop when you
can&#39;t find anything better&quot; or &quot;keep improving your solution until 7am
tomorrow&quot; is both an easy and a relative piece of information for a user
 to give the algorithm, while it is hard for the algorithm to guess at
when to stop. See, the genetic algorithm can just keep. on. going. It
will find try to find better and better solutions until you tell it to
stop. This makes sense. There are a million ways, for example, to get
food at the end of a work day. However, I usually know as a user when I
want to stop looking for a better solutions. Telling the algorithm when
to stop is telling the algorithm when the solution it&#39;s trying to find
is &quot;good enough&quot;. Therefore, this parameter also makes sense for the
user to provide.&lt;br /&gt;
&lt;br /&gt;It&#39;s the other three that can be
thorns in a user&#39;s side. There is no intuition that can help the user
determine what &#39;kill-off rate&#39;, &#39;mutation rate&#39;, or &#39;population size&#39;.
These three parameters need to be set and set well, but the only way a 
user would
know how to set them is trial and error. The New Genetic Algorithm is 
cool, not only because of its back-end efficiency, but its front-end 
user friendliness: &lt;i&gt;it knows how to set those three parameters for you.&lt;/i&gt; &lt;br /&gt;

&lt;h1&gt;
Setting The Parameters&lt;/h1&gt;
&lt;br /&gt;
&lt;h2&gt;
Kill-Off Rate&lt;/h2&gt;
&lt;br /&gt;
Most genetic algorithms will ask you to specify a 
kill-off rate: a percentage of your population which should be killed 
off at every step of the algorithm (each &quot;season&quot;, if you will). It asks
 the question: at each iteration, how many of the &quot;weak&quot; of the 
population should die? This rate also dictates the number of new 
solutions created at each step, since in general the algorithm should 
deal with a fixed population size.&lt;br /&gt;
&lt;br /&gt;So what should our 
algorithm choose as its kill-off rate? 5%? 10%? 2%? All of these choices
 seem so arbitrary. There really isn&#39;t a choice I have found that makes 
more sense than the others. Too many killed off, means you won&#39;t get as 
good of results as you could have. Too few, and it will take a while to 
get there.&lt;br /&gt;
&lt;br /&gt;It should be stated here that kill-off rate 
is kind of related to something which in other algorithms is called 
&quot;learning rate&quot;. The higher the kill-off rate, the faster the solutions 
will improve; however, the slower the kill-off rate, the better the 
results will ultimately be, even if it takes a while to get there. The 
kill-off rate represents the &#39;price/quality&#39; tradeoff: more quality = 
more time = smaller kill-off rate; less quality = faster running = 
greater kill-off rate. What would be &lt;i&gt;really&lt;/i&gt; cool is if the 
algorithm could choose the kill-off rate based on how much time it was 
given to run (when to stop). That way the user only need specify when to
 stop and the algorithm knows how long to run.&lt;br /&gt;
In that light, and 
for reasons that will become clear later on in this series, I simply 
chose to kill of one (&lt;code&gt;1&lt;/code&gt;) solution per step. This essentially means that 
the population size ultimately decides this kill-off rate. If I have &lt;code&gt;100&lt;/code&gt;
 solutions in my population, that means the kill-off rate is &lt;code&gt;1%&lt;/code&gt;. If I 
have only &lt;code&gt;10&lt;/code&gt;, it means my kill-off rate is &lt;code&gt;10%&lt;/code&gt;. This may seem like a bad
 thing, but what it does is that &lt;i&gt;it allows us to choose kill-off rate based on population size&lt;/i&gt;.
 In other words, by making kill-off rate dependent on population size, 
we can control how fast the algorithm learns by only regulating one 
variable (the size of the population). This makes thinking about how to 
tell the algorithm how fast or slow to learn much easier. It also makes 
the single step of the algorithm &lt;i&gt;very&lt;/i&gt; fast and gives it more predictable results.&lt;br /&gt;

&lt;br /&gt;
&lt;h2&gt;
Mutation Rate&lt;/h2&gt;
&lt;br /&gt;
A small word should be put here about how creation of new solutions in the population works.&lt;br /&gt;

&lt;br /&gt;
Mutation relies on the fact that, &lt;i&gt;all bit strings of length &lt;code&gt;n&lt;/code&gt; specify a solution&lt;/i&gt;.
 It flips one of its bits at random.&amp;nbsp; The genetic algorithm doesn&#39;t see 
the solution for a solution; rather, it just sees a bunch of 1&#39;s and 
0&#39;s. This is consistent with nature. Nature doesn&#39;t see a bacteria for 
what it is; it just sees a bunch of DNA. The 1&#39;s and 0&#39;s are the 
solution&#39;s &quot;DNA&quot;. Thus by flipping one of the random bits in the 
solution, we &lt;i&gt;mutate&lt;/i&gt; the solution.&lt;br /&gt;
&lt;br /&gt;There is a small amount of math involved here, but not bad; just enough to keep things interesting.&lt;br /&gt;

We
 want to choose a mutation rate (the percentage of the population 
getting this random bit flipped) intelligently. The new algorithm is 
herein designed to choose it to maximize the &lt;i&gt;diversity&lt;/i&gt; of the population.&lt;br /&gt;

&lt;br /&gt;
Here
 in our new algorithm, we want a highly diverse population. If you have 
many solutions that are roughly the same, what is the benefit of a 
population at all?&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
A Side Note About How We Create New Solutions&lt;/h4&gt;
&lt;br /&gt;
In the new algorithm, we will use &lt;a href=&quot;https://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29#One-point_crossover&quot;&gt;single crossover&lt;/a&gt;
 to create a new solution. There are lots of ways to create new 
solutions, but as we intimated in the beginning, we like to keep things 
simple in this new algorithm. This just means we pick a random number 
between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; (the size of the solutions -- the number of bits they 
contain). Call that number &lt;code&gt;p&lt;/code&gt;. The first &lt;code&gt;p&lt;/code&gt; bits come from the first 
&lt;code&gt;p&lt;/code&gt; bits of one solution (the &quot;mom&quot;) and the rest of the bits come from 
the other solution (the &quot;dad&quot;).&lt;br /&gt;
&lt;br /&gt;Who shall we chose to 
make new solutions? the two best, or part of the &#39;party&#39; of the elite of
 the population? Perhaps we could, but here in our new algorithm, let&#39;s 
keep things simple. We will simply take two random solutions from the 
population and pair them up to create a new solution. &lt;br /&gt;
&lt;br /&gt;&lt;h4&gt;
Why This is Important to Choosing Mutation Rate&lt;/h4&gt;
&lt;br /&gt;Now let&#39;s 
reiterate our problem. We need to choose mutation rate to maximize 
diversity of the population. In order to ascertain diversity, we need a 
population sample.&lt;br /&gt;
&lt;br /&gt;But we just chose two solutions at 
random to create a new solution. Why don&#39;t we just use the two solutions
 we just chose as a small &quot;sample&quot; of the population of solutions? That 
way, we only need to retrieve two solutions per iteration, kill one off,
 create one, and possibly mutate one. Genious! then the iterations can 
be done &lt;i&gt;very fast&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;How do we determine if the 
population is &quot;diverse&quot;? Simple: we count up how many bits at each 
position from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt; in the bit strings of the mom and dad solutions
 are the same. The more that are the same, the more &quot;the same&quot; the 
population is and the more it is due for a mutation. Then, if we do 
decide to mutate a solution, we will simply mutate one of the solutions 
and re-insert it back into our population.&lt;br /&gt;
&lt;br /&gt;We will use this formula to determine the probability of whether we should mutate one of the parents:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;P(m) = 4*(1/2*k/n - 1/2)^2&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
Where &lt;code&gt;P(m)&lt;/code&gt; is the probability that we should mutate one of the solutions, &lt;code&gt;n&lt;/code&gt; is
 the number of bit positions for solutions, and &lt;code&gt;k&lt;/code&gt; is the number of bit
 positions where both parents share the same value.&lt;br /&gt;
&lt;br /&gt;This is a nice, easy-to-compute, bowl-shaped function that actually looks a lot like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Entropy_%28information_theory%29&quot;&gt;information entropy function&lt;/a&gt; for two values. That&#39;s math-speak for &quot;it worky.&quot;&lt;br /&gt;
&lt;br /&gt;Think
 about it -- If about half the bits are the same, which you would expect
 that from two random solutions, the probability of mutation is small, 
since the two solutions are expected to look pretty different from each 
other -- around half their positions are different. The closer &lt;code&gt;k/n&lt;/code&gt; 
gets to &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;, though, that value goes to &lt;code&gt;1&lt;/code&gt;, or &lt;code&gt;100%&lt;/code&gt;, meaning that one 
of them really should be mutated, since each solution looks too much 
like the other, or that they look like polar opposites, both types of 
which we would not expect in a more diverse population.&lt;br /&gt;
&lt;br /&gt;After
 we have computed &lt;code&gt;P(m)&lt;/code&gt;, then we just get a random number between &lt;code&gt;0&lt;/code&gt; and
 1. Call it &lt;code&gt;r&lt;/code&gt;. If &lt;code&gt;r &amp;lt; P(m)&lt;/code&gt;, then we mutate one of the new 
solutions and re-introduce it to the population. If it isn&#39;t, we simply 
put both parents back un-mutated.&lt;br /&gt;
&lt;br /&gt;There! we have chosen
 a good method for choosing mutation rate dynamically. It is chosen at 
each iteration, is easy to compute, and makes sense for the goal.&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;
Population Size&lt;/h3&gt;
&lt;br /&gt;As New Genetic Algorithm designers, it&#39;s our job 
to figure out how best to determine population size. This is the size of
 the RankedSet discussed in the last post of the number of &quot;indigenous&quot; 
solutions that we&#39;ll keep around. We need a base population if we want 
to kill some off and create more and still have the genetic algorithm to
 work. So how do we choose population size?&lt;br /&gt;
&lt;br /&gt;Remember 
earlier, when I said that by determining population size and keeping the
 kill-off rate at one solution, we determine the &#39;learning rate&#39;? When 
we have a small population size, say 10, the learning rate/kill off rate
 is &lt;code&gt;1 / 10 = 10%&lt;/code&gt;. This means the algorithm will improve fast, but also 
plateu fast.&lt;br /&gt;
&lt;br /&gt;Why don&#39;t we just wait for it to plateu at
 some improvement level, then when it does, we increase the size of the 
population? By doing so, we decrease the learning rate, allowing the 
algorithm to find an even better solution, even if more slowly.&lt;br /&gt;
&lt;br /&gt;To
 keep things simple, let&#39;s just say this: We&#39;ll start off at a 
population size of &lt;code&gt;16&lt;/code&gt;. When we find that no more &quot;improvement&quot; is to be 
found within the population, we double population size and continue 
iterating. We keep doing this until we are supposed to stop, which is 
something that the user supplies!&lt;br /&gt;
&lt;br /&gt;Simple, easy, intuitive, and easy to implement. These are the goals of the new genetic algorithm.&lt;br /&gt;


</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4803952895931388668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/09/the-new-genetic-aglorithm-what-makes-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4803952895931388668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4803952895931388668'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/09/the-new-genetic-aglorithm-what-makes-it.html' title='The New Genetic Aglorithm: What Makes It New'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-6690030536965217799</id><published>2013-07-05T19:16:00.003-07:00</published><updated>2013-07-19T18:53:29.258-07:00</updated><title type='text'>The RankedSet: Optimization&#39;s Best Friend</title><content type='html'>&lt;br /&gt;
This post is the second post about the &#39;New Genetic Algorithm&#39; that I posted about previously.&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;
What We Need&lt;/h1&gt;
See, when you&#39;re running the genetic algorithm -- that nifty way to solve problems by computer -- you need to store different solutions to the same problem. For example, suppose I need dinner for my family tonight. Do I cook at home, grab some fast food, or buy a TV dinner at the local grocery market? These are different solutions to the same problem: my family needs food.&lt;br /&gt;
&lt;br /&gt;
While the genetic algorithm (any genetic algorithm, including this new one) is running, it needs to maintain a &quot;population&quot; of such solutions. It keeps around, say, 100 solutions, kills off some, and adds new ones, but it always stores so many solutions (e.g. 100) at all times. In my new genetic algorithm, it will be important for reasons explained in a later post for the algorithm to be able to figure out the &lt;i&gt;rank&lt;/i&gt; of each solution. Rather than knowing how much better one solution is from another, I feel it is important only to tell which solution is better than the other. When we make a buying decision, it does not matter if one option is a little bit better or way better, we usually just take the better option. This idea is important, and in the algorithm it will become important to be able to find a solution within the &quot;population&quot; and be able also to delete it &lt;i&gt;based on its rank&lt;/i&gt;. I need to be able to say to the data structure, &quot;give me the 45th best solution&quot; and out it pops. I also need to be able to say, &quot;kill off the 32nd solution&quot;. So, in order to store the population so that I can easily find, delete (kill off), insert (introduce) a solution into my population, the question is: what is the best way to store my population in a computer?&lt;br /&gt;
&lt;br /&gt;
It turns out, there really isn&#39;t a data structure in any standard library I&#39;ve found that can do the job. By the way, for those purist logicians who are craving a formal specification of what &#39;the job&#39; is, sink your teeth into this:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The data structure needs to store information about each solution. If this is the &#39;bring home the bacon&#39; example, it needs to store stuff like &#39;store location&#39;, &#39;what to buy&#39;, etc.&lt;/li&gt;
&lt;li&gt;The data structure needs to store information about the &lt;i&gt;rank&lt;/i&gt; (e.g., best, second-best, 43rd-best) of each solution.&lt;/li&gt;
&lt;li&gt;The data structure needs to have efficient retrieval, deletion, and insertion. It needs to be able to delete a solution given its rank, and retrieve a solution given its rank.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h1&gt;
Fanfare, Please: Enter the RankedSet&lt;/h1&gt;
&lt;h3&gt;
Why We Like It&lt;/h3&gt;
&lt;div&gt;
The RankedSet will solve the problems I have stated above. You can store a solution to a problem in it, you can tell the set how great the solution is, and it will assign ranks for you based on how good each solution is. It provides retrieval and deletion based on rank and all retrieval, deletion, and insertion runs in logarhmic time. For those non-nerds out there, that means it does what we want it to, and it does it at speeds that take the cake.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here&#39;s how it works: when we insert a solution into the set, we give it two values: how good the solution is, which we will call the &lt;i&gt;index&lt;/i&gt;, and then the information about the solution itself, which we will call the &lt;i&gt;payload&lt;/i&gt;. Since we&#39;ll rank the solutions in the set based on the first value, it needs to be a number -- a score, or perhaps in some cases, a monetary amount, etc. The payload can be anything we want, but in this case it is information about the different solution that we will put here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
How It Works&lt;/h3&gt;
&lt;div&gt;
But how does it &lt;i&gt;work&lt;/i&gt;, you say. That&#39;s the juicy part, right?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Computer Scientists know that what I am about to describe, is, basically, a &lt;i&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Binary_search_tree&quot;&gt;Binary Search Tree&lt;/a&gt;&lt;/i&gt;, or BST. Each solution has at most two &quot;children&quot; solutions--one with a greater index than itself, and one with a smaller index.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
With each solution is stored three things:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;The solution information itself.&lt;/li&gt;
&lt;li&gt;How &quot;good&quot; the solution is.&lt;/li&gt;
&lt;li&gt;How many other solutions are &quot;downstream&quot;, or, how many &quot;descendants&quot; the solution has (including itself).&lt;/li&gt;
&lt;/ol&gt;
It&#39;s number 3 in the above list that&#39;s the interesting bit. every other part of the description of how the solutions are stored is just a regular ol&#39; BST, easily found in most any standard library in most any computer language. But no BST I&#39;ve ever found has #3 in the above list stored in it, and so cannot function as a RankedSet.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note that the value for #3 can never be empty. If there is a solution stored with no &quot;children&quot; solutions, #3 value is just &quot;1&quot;, since it is the number of solutions that are descended from a node, &lt;i&gt;including itself&lt;/i&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If every solution in the tree stores #3, then it becomes easy for the BST to look up a solution based on rank. Say that I need the 13th best solution in the BST. I ask the &quot;root&quot; node (the very first solution, with no parents and all children) to give me the 13th best. It asks the &#39;greater&#39; of its children how many children it has. Say that number is 10. To few. It asks its lesser child again how many children that it has, which might be 20. So, it tells its lesser child to find the 2nd best solution in its family (13 minus the 10 best on the greater side, take away the root node itself, which leaves 2). If that sound hokey to you, then just trust me: it works, and it&#39;s fast.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Further explanation would boggle the mind of those of my non-egg-head readers, and is not necessary for those already familiar with binary search trees. Suffice it to say that caching the number of descendants of a solution, including the solution itself, allows us to find and delete solutions based on rank.&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h1&gt;
So What&#39;s It All Mean?&lt;/h1&gt;
&lt;br /&gt;
&lt;div&gt;
It means that we can now construct an algorithm that does not have to concern itself with how great a solution is, only if it is the best one. At the same time, it also means that the algorithm only has to know how good a solution is when it is inserted into the population, and from then on it need only talk about weeding out solutions that are weak, like the 75th best solution, and promoting the strong ones, like the 2nd solution. It means that it can talk about the rank of those solutions without ever actually retrieving them until it is time to kill the weak and create the strong. This makes our algorithm really &lt;i&gt;fast&lt;/i&gt;&amp;nbsp;and very &lt;i&gt;effective.&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
&lt;h1&gt;
Up Next&lt;/h1&gt;
In the next post I will talk about how the algorithm uses the RankedSet, how it chooses how many weak to kill off and spawn, how it chooses how many solutions to mutate, and how easy those choices make it for programmers to use the new genetic algorithm to solve the next big problems.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/6690030536965217799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/07/the-rankedset-optimizations-best-friend.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/6690030536965217799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/6690030536965217799'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/07/the-rankedset-optimizations-best-friend.html' title='The RankedSet: Optimization&#39;s Best Friend'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-1625343037676796451</id><published>2013-05-20T09:23:00.002-07:00</published><updated>2013-07-05T16:54:35.587-07:00</updated><title type='text'>A New Genetic Algorithm</title><content type='html'>I have recently been fascinated with the genetic algorithm, which is a method that allows you to solve pretty much any big problem via computer, like finding the most nutritional, affordable lunches for a week for your kids, or what&#39;s the best NFL schedule (funny that these problems are provably equivalent).&lt;br /&gt;
&lt;br /&gt;
The idea is simple. generate a bunch of mediocre solutions, kill off (eliminate) the weak ones, use the stronger ones to sire more solutions, mutate a gene (aspect) of some solution or other just to shake things up, and repeat.&lt;br /&gt;
&lt;br /&gt;
The problem is all of the different ways to do it. Should we mutate 5% of the solutions, or 10%? How many solutions should we kill off at a time? How many should we make? There are alot of design decisions to make when using this algorithm.&lt;br /&gt;
&lt;br /&gt;
And then there&#39;s efficiency to think about. How should the solutions be represented (e.g., what stats should be encoded)? What data structures should be used? What complexity class is acceptable (has to do with how much time the program takes to run)? These questions may sound unimportant from a business perspective, but it&#39;s the difference in an app between &#39;wow, that was zippy&#39; and &#39;that sure took a long time to load&#39;.&lt;br /&gt;
&lt;br /&gt;
The &#39;data structure/data representation&#39; question is particularly important because not only does it deal with how fast the program runs, but how maintable the code base will be in the future. When, as a programmer, I code up a solution to a problem, it is very difficult to change the way the data is represented and stored in the future.&lt;br /&gt;
&lt;br /&gt;
I have given all these problems some thought, and I have come up with (I believe) a very good solution. The data representation is versatile. The data structure is maintainable, efficient, and convenient. Best of all, I have found a convenient way to get rid of all those parameters (i.e., I have adequately answered all of the &#39;how/what&#39; questions about the algorithm, listed above).&lt;br /&gt;
&lt;br /&gt;
I will post a series of articles detailing what I did to create a genetic algorithm which needs only be given a fitness function and the size of the population of solutions -- nothing else. It is fast, usable in a highly varied number of fields, and its operation is intuitive.&lt;br /&gt;
&lt;br /&gt;
My first post will deal with the data structure / data representation problem. My second will deal with removing the how-many-to-kill-off/how-many-to-reproduce/how-many-to-mutate problem. My third post will tie it all together. Let me know in the comments below to join the conversation and let me know how I&#39;m doing as I go. I will try to answer any questions given.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/1625343037676796451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2013/05/a-new-genetic-algorithm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/1625343037676796451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/1625343037676796451'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2013/05/a-new-genetic-algorithm.html' title='A New Genetic Algorithm'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4775717862504239262</id><published>2012-04-18T17:43:00.000-07:00</published><updated>2012-04-18T17:43:19.432-07:00</updated><title type='text'>2/3 Swing Follow-up</title><content type='html'>So the algorithm I spoke of in my last post is actually very&amp;nbsp;similar&amp;nbsp;to an algorithm known as v-opt. The difference between 2/3 swing and v-opt is that in v-opt, before ensuring that the solution is an n-opt minima, first ensures that it is also a k-minima for all k &amp;lt; n. So then, the solution is&amp;nbsp;guaranteed&amp;nbsp;to be &amp;nbsp;gets to a 2-opt minima, then a 3-opt minima, and stops, whereas mine swings back and forth. This difference is further seen when 4-opt is introduced. Then, v-opt would find a 2-opt minima, then a three-opt minima, then ensure it is at a two-opt minima again, then ensure it is in a three-opt minima again, etc. Finally, when both 2-opt and 3-opt minima is found, it ensures it is in a four-opt minima, then a two-opt minima, then a three-opt minima, then a two-opt minima again, until it is in both 2- and 3-opt minimas before it checks for 4-opt minima, etc. I know, kinda confusing.&lt;br /&gt;
Mine just ensures it&#39;s in a 2-opt minima, and goes round-robin instead of making sure the solution is a minima of all opt&#39;s below the current one (both 2- and 3- opt before we ensure 4-optimality). It just goes round and round - 2-opt, then 3-, then 4-, then 2-, then &amp;nbsp;3-, then 4-,... I found this approach did alot better than conventional v-opt as I understand it.&lt;br /&gt;
That may have been a&amp;nbsp;little confusing, but I wanted to make sure I tied in my own research with what&#39;s already out there.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4775717862504239262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2012/04/23-swing-follow-up.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4775717862504239262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4775717862504239262'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2012/04/23-swing-follow-up.html' title='2/3 Swing Follow-up'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-7909413123022708890</id><published>2012-02-28T07:43:00.003-08:00</published><updated>2012-02-28T07:51:13.665-08:00</updated><title type='text'>The TSP Refinement Solution, Continued: 2/3 Swing</title><content type='html'>&lt;span style=&quot;font-family: inherit;&quot;&gt;The work on the algorithm I spoke of in my last post bore fruit! It works very well and uses perhaps previously-unbeknownst-insight. The outline of the finished product I lay before you now.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The attached contains the empirical data I gathered about how well my algorithm works.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;I received some surprises, and other things did not surprise me. I guessed my algorithm would perform somewhere around O[(n^3)log(n)], and as you can see by the graph, it is quite possible that it did. I was surprised to find, however, that the relationship between how well the greedy algorithm did versus how well my solver did (I call it the &quot;2/3 swing&quot; algorithm) was linear - about 1.3x better than greedy. Perhaps this is because I started out with greedy and can only get so far refining any given solution. Perhaps if I started out with a closer approximation, I might get closer to optimality.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;You see, the way my algorithm works is that it takes an initial arbitrary solution - in the case of the data provided, the algorithm started out with a random greedy solution - and, essentially, then gets into a 2-opt local minima. But the insight I gained in creating this algorithm is that a 2-opt local minima is not necessarily a 3-opt local minima. In fact, it rarely is. This is like multi-dimensional gradient descent - as there is rarely a minima across all dimensions in gradient descent, so there is rarely a minima across all opt&#39;s. At least, that is the idea of the algorithm.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Here&#39;s another clincher: getting into a 2-opt minima for assymetric, incomplete graphs (TSP city maps) has roughly the same complexity as getting into a 3-opt minima, since a linearly-large portion of the path must be reversed for each check to see if the change is an improvement. &amp;nbsp;This makes a thorough 2-opt check, whose search space is in O(n^2), take O(n^3) time. To find a 3-opt local minima, the search space is in O(n^3) and the check is in O(1), so finding a local 2-opt minima, then trying to find a local 3-opt minima, doesn&#39;t cost much more by way of complexity, residing only in a constant factor increase in time.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The way that this algorithm gets itself into O(n^3*log(n)) time (or O(n^3.22), if the graph&#39;s regression line is to be believed) is by continually &quot;swinging&quot; back and forth between using 2-opt and 3-opt to find the next minima, so that a series of operations in O(n^3) time is looped over a few times. Between using 2-opt and 3-opt, city swapping is employed (taking two arbitrary cities on the best route so far and switching their places as far as order of visitation if such a switch improves the route&#39;s score) so as to &quot;mix the bag&quot; between swings. This operation is a small subset of 4-opt, and because it is only in O(n^2) it does not hurt complexity much. Additionaly, since this algorithm works on asymmetric city maps, a reversal of the direction of the route is checked to see if it improves the score on each &quot;swing&quot;. This check is linear in time and also does not greatly affect the complexity of the algorithm. Thus the algorithm follows:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;best route so far = (initial-approximation-solution)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;best cost = infinity&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;while best cost &amp;gt; best route so far&#39;s cost&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; best cost = best route so far&#39;s cost&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; reverse best route so far if that improves it&#39;s score&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; best route so far = (next 2-opt local minima)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; best route so far = (next swap-cities local minima)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; best route so far = (next 3-opt local minima)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp; &amp;nbsp; best route so far = (next swap-cities local minima)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;return best route so far&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;As I cannot post the original data, I will only post the graphs. Original data upon request.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Technical Data:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Platform used: C# on .NET 4, running on an Acer Aspire One 532 netbook&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Initial solution (used in refinement): random greedy&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;City Map: Assymetric, Incomplete&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Acknowledgements:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;I used the C# TSP Framework provided by the CS department of Brigham Young University.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Code was used in studying this problem which was written by Jimmy Hales (see previous post), although all the code used in the 2/3 swing algorithm is original to the author of this post. Dr. Tony Martinez of Brigham Young University served as adviser during my study of this algorithm, and thanks to him I continued to work on it.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1i8MoNdKeHNwI7IdypI9oUIW65SnvYziE9iMIXEYI07fTWOd5g3Gi2O261mePjbbc1HBJHH9NPu3ZcYb563HFHcN-BVcVYhFZD62crtVqBh47EyVBI1QHVbJgu8zqxReTWXuRWrS5Dk9R/s1600/my+scores+vs+greedy.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;207&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1i8MoNdKeHNwI7IdypI9oUIW65SnvYziE9iMIXEYI07fTWOd5g3Gi2O261mePjbbc1HBJHH9NPu3ZcYb563HFHcN-BVcVYhFZD62crtVqBh47EyVBI1QHVbJgu8zqxReTWXuRWrS5Dk9R/s400/my+scores+vs+greedy.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk0YSVer8ZTsThtxlMbsZg3mx_-OjzxnkiwBUCJcbris8bc8-EtgP3IBEIUIy1IAr-ztHmT22GLmOs1BRgb94ABvr0U0pvzYdwC4Y6Mx9fDt4EBs_oi6S_Ac_aGur8ENsEoaLYuMqyRLjo/s1600/my+times.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk0YSVer8ZTsThtxlMbsZg3mx_-OjzxnkiwBUCJcbris8bc8-EtgP3IBEIUIy1IAr-ztHmT22GLmOs1BRgb94ABvr0U0pvzYdwC4Y6Mx9fDt4EBs_oi6S_Ac_aGur8ENsEoaLYuMqyRLjo/s400/my+times.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/7909413123022708890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2012/02/tsp-refinement-solution-continued-23.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7909413123022708890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7909413123022708890'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2012/02/tsp-refinement-solution-continued-23.html' title='The TSP Refinement Solution, Continued: 2/3 Swing'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1i8MoNdKeHNwI7IdypI9oUIW65SnvYziE9iMIXEYI07fTWOd5g3Gi2O261mePjbbc1HBJHH9NPu3ZcYb563HFHcN-BVcVYhFZD62crtVqBh47EyVBI1QHVbJgu8zqxReTWXuRWrS5Dk9R/s72-c/my+scores+vs+greedy.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-7101160060343879835</id><published>2012-01-04T19:37:00.000-08:00</published><updated>2012-01-04T19:52:09.108-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="travelling salesman"/><title type='text'>An Idea for the Refinement of a TSP Solution</title><content type='html'>&lt;span style=&quot;font-family: inherit;&quot;&gt;Although I found through experiment that my probabilistic approach to finding a good TSP solution didn&#39;t work so well, I did manage to find a polynomial time algorithm that can take an arbitrary solution to the&amp;nbsp;Traveling Salesperson Problem (TSP) and refine it to the optimal solution (with what I have tested so far). I do not know if this polynomial refinement-to-optimality is possible for solutions bigger than 20, as the exponential branch-and-bound solver at my disposal can&#39;t do very much given the hardware I have on which to run it.&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;background-color: white; font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Now, I think what I have found here MIGHT be awesome.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;At any rate, I can explain what it does.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;First, we assume an asymmetric directed graph of cites, wherein not every possible edge exists -- i.e. The number of edges in the graph |E| &amp;lt; |V|^2, where |V| is the number of vertices (cities) in the graph (map of cities). For simplicity, if an edge does not exist from one city to another, the reverse edge also does not exist. It can be quickly checked that this problem is still NP-Complete.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;We may take this graph to be a map of roads between cities, and the weights on the edges (roads) to be a score of them based on the distance between the cities and the elevation difference between the cities, i.e. if one city is higher in elevation than another, the edge going from the higher to the lower is going to be scored lower than the edge which goes from the lower to the higher, because it is easier to go downhill. Looking at such a real map of cities and creating a graph from it, by scoring the edges as above, we find a distinct pattern in the optimal solution to the traveling salesman tour of the cities considered:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;In some sense, the solution forms a &quot;polygon&quot; in the sense that no loops are created. So, this:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtIw5jv-yjbUp88YckUK4GGbxz0Lu-ZLCb1FhXXsB6qQZDeBhd5wyN1liwhlASkn-u1P9SVpHm1II19aP0JMs3aAuekx_ig4mJ9Arj7xtZqe3A-Id6u7CcBmtjCcEOJSCDX-b0a1HVbzfW/s1600/optimal-tour.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;span style=&quot;background-color: white; color: black; font-family: inherit;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtIw5jv-yjbUp88YckUK4GGbxz0Lu-ZLCb1FhXXsB6qQZDeBhd5wyN1liwhlASkn-u1P9SVpHm1II19aP0JMs3aAuekx_ig4mJ9Arj7xtZqe3A-Id6u7CcBmtjCcEOJSCDX-b0a1HVbzfW/s320/optimal-tour.png&quot; width=&quot;303&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;would be a better solution than this:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir82RUza_gQOezGL4Meq4jxmdRQew475H77SwcOGUdZ6Y0NyHhVuXTAJMpMW5riOccZgsH7PApA-xwR1IC1d1JOVqwZ5rK367wpiKRWgSXthV7GCnjpKDorTpwDnyir7e19c8LIG9k3XWs/s1600/twisted.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir82RUza_gQOezGL4Meq4jxmdRQew475H77SwcOGUdZ6Y0NyHhVuXTAJMpMW5riOccZgsH7PApA-xwR1IC1d1JOVqwZ5rK367wpiKRWgSXthV7GCnjpKDorTpwDnyir7e19c8LIG9k3XWs/s320/twisted.png&quot; width=&quot;303&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Provided we are looking at the &quot;actual&quot; city map, this is a fairly good heuristic for &quot;goodness&quot; of a solution, if not a requirement for optimality. Looking at the actual city map is important because the actual euclidean distance between cities is taken into account in the scoring of edges, and so these &quot;twists&quot; show up on the actual map, whereas if we just have the graph information, this intuition would not make sense since placement of the node on paper of the equivalent graph has nothing to do with the edge weight. Again, it should be noted that the graph (city map) upon which we consider is asymetric and incomplete, and so is still worthy of discussion.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;To further shed light on this discussion, it will be assumed that the optimal tour through a given number of cities will be represented by a list of cities, with the order that the city appears in the list being the order of its visitation on the TSP tour. I now take from an excerpt of an email I sent to my CS professor Dr. Tony Martinez on the subject.&lt;/span&gt;&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
To refine a given approximate solution, I observed (as explained above) that approximate solutions often have &quot;twists&quot; in them - that is, they were not polygons since their vertices crossed. So I take the solution and try untwisting any arbitrary segment of the solution (that is, reversing that segment - e.g. take the segment # 2, 3, 4, 1, 5 and change it to &amp;nbsp;# 5, 1, 4, 3, 2) and see if that operation improves the score. If it does, I return the improved route, else I return the route the untwisting method was given.&amp;nbsp;&lt;i&gt;[author&#39;s comment: if done properly, this part of the algorithm can be done in O(n^2) time.]&amp;nbsp;&lt;/i&gt;&lt;br /&gt;
Now (empirically) I have observed that the approximate solution is now a polygon (no twists). But it may not be the &quot;right&quot; polygon. To try a different polygon, I simply take an arbitrary subsegment of the solution and splice it into a different part of the whole solution. Example: If we have a solution of Cities # 2, 4, 7, 5, 8, 1, we take an arbitrary sub segment of cities # 4, 7, 5 and try the solution where they are inserted in between 8 and 1 to produce # 2, 8, 4, 7, 5, 1. I try all such possible splice combinations, and see if they improve the score, returning any improvements. This search space, though it be search by brute force, is only O(n^3) large (what&#39;s more, being a brute force search, this and other improvement spaces given below can be searched in parallel). I find (again, empirically with our CS312 TSP&amp;nbsp;&lt;i&gt;[Framework]&lt;/i&gt;&amp;nbsp;code) that this operation changes the &quot;polygon&quot; to a more optimal one.Finally, for sugar, I take this new and improved solution and select two arbitrary cities along its path and swap them, so that a tour which was city # 2, 3, 8, 7, 1, 4 becomes # 2, 1, 8, 7, 3, 4 if we swap the cities 1 and 3, thus changing the order in which they are visited.&lt;br /&gt;
I repeat these three steps - untwisting, segment swapping, and city swapping - for as long as they &quot;help&quot;, or as long as any one of them return an improved solution. I find that the number of repetitions is usually small - 3 or 4 times for 50 cities (when it is given a best-of-greedy initial approximate solution, which is an algorithm in O(n^2) time). &amp;nbsp;&lt;i&gt;[author&#39;s comment: these were my results when, instead of stopping during untwisting/segment splicing/city swapping at the first improvement found, I tried all available twists/splices/swaps at one time and used the best of those. The results might be higher if the suggested stop-at-first-improvement approach is taken.]&lt;/i&gt;&lt;br /&gt;
For 20 Cities, I have &amp;nbsp;verified that it spits out the optimal solution over and over again, and in much faster time than branch and bound. I do not have the resources to try for the optimal solution for more than 20 cities using C# code on my laptop&amp;nbsp;&lt;i&gt;[which is a netbook. Details: Acer AspireOne 532h, 2GB RAM, 1.66 GHz processor, running C# .NET executable under Windows 7 Starter]&lt;/i&gt;.&lt;/span&gt;&lt;/blockquote&gt;&lt;span style=&quot;background-color: white; font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Thus, I believe this whole algorithm runs in O(N^4) time, which is certainly not exponential&lt;/b&gt;. The inner loop (untwisting, splicing, swapping) can be done in O(N^3) time and O(N) space, and it is entirely possible that in fact this algorithm is in O(n^3*log N) time, more empirical study needs to be done to decide if that is indeed the case. While largely untested for bigger N, in the tests I have run it finds the optimal solution every time for city maps with city counts &amp;lt; 20. I know, it&#39;s not a big number, but this may still be a very good refinement of a given solution, if not a way to find the optimal solution.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;I wonder if anyone could try this method of solution refinement and corroborate my results&lt;/b&gt;. Thank you all so much for your comments. I hope someone can further this effort by trying this refinement solution out themselves and comparing their results to known optimal solutions of the graphs upon which they are testing this refinement solution.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;u&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Acknowledgments: The code for the Branch-and-Bound solver I used is authored by Jimmy Hales. The C# framework out of which I performed the empirical tests was given to me by the CS Department of Brigham Young University as part of a class assignment for CS312, mentioned in the above letter excerpt as the CS312 TSP (Framework) code.&lt;/span&gt;&lt;/u&gt;&lt;/i&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/7101160060343879835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2012/01/idea-for-refinement-of-tsp-solution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7101160060343879835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7101160060343879835'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2012/01/idea-for-refinement-of-tsp-solution.html' title='An Idea for the Refinement of a TSP Solution'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtIw5jv-yjbUp88YckUK4GGbxz0Lu-ZLCb1FhXXsB6qQZDeBhd5wyN1liwhlASkn-u1P9SVpHm1II19aP0JMs3aAuekx_ig4mJ9Arj7xtZqe3A-Id6u7CcBmtjCcEOJSCDX-b0a1HVbzfW/s72-c/optimal-tour.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4490551503804501984</id><published>2012-01-04T17:57:00.000-08:00</published><updated>2012-01-04T17:57:44.628-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fail"/><category scheme="http://www.blogger.com/atom/ns#" term="travelling salesman"/><title type='text'>Update on the Probabilistic TSP Algorithm</title><content type='html'>Basically?&lt;br /&gt;
&lt;br /&gt;
It failed. Miserably. If we rated the edges based on what I said below, it may have even given us the worst possible path (a great achievement if it were so!) and if we took the edge weights into account in the ratings, the algorithm pretty much spat out roughly what a greedy solution would have anyway. However, I am glad to have done it. It gave me a lot to think about with the Traveling Salesperson problem.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4490551503804501984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2012/01/update-on-probabilistic-tsp-algorithm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4490551503804501984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4490551503804501984'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2012/01/update-on-probabilistic-tsp-algorithm.html' title='Update on the Probabilistic TSP Algorithm'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-885112374212368338</id><published>2011-11-22T06:05:00.000-08:00</published><updated>2011-11-22T06:05:16.519-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="monte carlo"/><category scheme="http://www.blogger.com/atom/ns#" term="travelling salesman"/><title type='text'>An Idea for a Probabilistic Approximation of the Solution to the Travelling Salesman Problem</title><content type='html'>In one of my classes here at Brigham Young, our group has been asked to come up with a unique idea for getting a good approximation to an optimal tour in the traveling salesman problem. Here&#39;s the idea I came up with.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
I wanted to bring statistics to the table, knowing about such algorithms as Monte Carlo Integration and others which took an unsolvable or hard problem and managed its size simply by taking samples of the bigger problem. The question was: How do you take a &quot;sample&quot; of an optimal traveling salesman tour?&lt;br /&gt;
&lt;br /&gt;
The idea came to select three cities at random, and then use Djikstra&#39;s Algorithm (or the Bellman-Ford Algorithm, in the case of negative edges) to find the shortest path from the first to the second, the second to the third, and the third back to the first again, making sure these paths do not cross. If there is no such path, we start over and pick three other random cities until we find a cycle in the way just described which connects them. Such a cycle we would call a &lt;i&gt;subcycle&lt;/i&gt;, and it would represent a sub-optimal approximation to the optimal tour (it takes the shortest route across a subset of the cities in the graph).&lt;br /&gt;
&lt;br /&gt;
Then, we rate the edges that were used in this subcycle. Initially, all the ratings associated with all the edges are 0. Each time we find a subcycle, we add &lt;i&gt;k/N&lt;/i&gt; to each edge that is used in that subcycle, where &lt;i&gt;k&lt;/i&gt; is the number of cities in the subcycle, and &lt;i&gt;N&lt;/i&gt; is the total number of cities in the graph.&lt;br /&gt;
&lt;br /&gt;
We then repeat this rating process hundreds or thousands of times, accumulating ratings for the edges that fall in these random subcycles as described above. In our group project, we have 30 seconds to find a solution for an arbitrarily-sized graph, so we just decided to run the rating process described above for 28 seconds, so that many samples could be taken.&lt;br /&gt;
&lt;br /&gt;
All that is left to do now is to take this information and create a solution. This is easily done by finding the first tour through all the cities, trying first the edges with the highest rating. The hope is that this final solution will be a good approximation to the optimal solution.&lt;br /&gt;
&lt;br /&gt;
We have not yet coded this up, but we are in the process of doing so. I&#39;ll post here to let the world know how well it worked out. I&#39;m very excited to see how well this works!&lt;br /&gt;
&lt;br /&gt;
I welcome any comments any of you may have on how well this may or may not work. Please feel free to respond to this post!</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/885112374212368338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/11/idea-for-probabilistic-approximation-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/885112374212368338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/885112374212368338'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/11/idea-for-probabilistic-approximation-of.html' title='An Idea for a Probabilistic Approximation of the Solution to the Travelling Salesman Problem'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-857692492268740901</id><published>2011-11-15T06:20:00.000-08:00</published><updated>2011-11-15T06:22:01.529-08:00</updated><title type='text'>.vimrc Goodies: Literal Lambda</title><content type='html'>I recently took to programming in racket after starting to take a class from Jay McCarthy (twitter: @jeapostrophe). Racket is a scheme-based language constructed specifically with industrial use in mind, which means it is based on some pretty solid theory while also posessing, like perl and php, a package management system (&lt;a href=&quot;http://planet.racket-lang.org/&quot;&gt;PLaneT&lt;/a&gt;), a JIT compiler, and other goodies that make it a great language to use in the real world.&lt;br /&gt;
&lt;br /&gt;
This language, along with perl (given that &#39;use lambda&#39; is invoked), allows the programmer to insert an acutal unicode lambda instead of the keyword &#39;lambda&#39;. DrRacket, racket&#39;s native IDE, allows you to insert this character by pressing &#39;CTRL+\&#39; . After looking at &lt;a href=&quot;http://vim.wikia.com/wiki/Working_with_Unicode&quot;&gt;this page&lt;/a&gt; and others, I found I could do this in vim, too.&lt;br /&gt;
&lt;br /&gt;
I put the following lines in my .vimrc file (this same entry worked in my _vimrc file, for the windows version, as well):&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;if has(&quot;multi_byte&quot;)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  if &amp;amp;termencoding == &quot;&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;    let &amp;amp;termencoding = &amp;amp;encoding&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  endif&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  set encoding=utf-8&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  setglobal fileencoding=utf-8&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  &quot;setglobal bomb&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;  set fileencodings=ucs-bom,utf-8,latin1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;endif&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;map! ^\ ^Qu03bb&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I inserted the special characters &#39;^\&#39; (CTRL-\) and ^Q (CTRL-Q) by using the normal vim way: in insert mode, type CTRL-V, then whatever control character you need to. For example, I inserted &#39;^\&#39; by typing CTRL-V, CTRL-\. For CTRL-Q, it was trickier. CTRL-Q is usually a specially bound command, so in order to insert it I had to use its octal number ordinal: CTRL-V, 017, were the keys I typed to insert that character.&lt;br /&gt;
&lt;br /&gt;
Now whenever I&#39;m editing a file, I type CTRL-\ and out pops a bonefied lambda!</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/857692492268740901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/11/vimrc-goodies-literal-lambda.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/857692492268740901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/857692492268740901'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/11/vimrc-goodies-literal-lambda.html' title='.vimrc Goodies: Literal Lambda'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4154388125996283547</id><published>2011-07-29T11:23:00.000-07:00</published><updated>2011-07-29T11:37:00.350-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="programming language"/><category scheme="http://www.blogger.com/atom/ns#" term="tag cloud"/><title type='text'>Tag Cloud of Programming Languages Based on Popularity</title><content type='html'>The following tag cloud was made by creating a text file with a given programing language&#39;s name repeated over and over, with one occurrence of the language&#39;s name appearing in the text file for each 100,000 results Google yielded for the phrase &#39;&quot;&lt;language&#39;s name=&quot;&quot;&gt;&quot; programming language&#39;. It has some interesting results. Please feel free to comment on its accuracy/inaccuracy, as I am very interested to know exactly how accurate the Google searches are. Enjoy!&lt;/language&#39;s&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUWB5-XiiJ0aRCO5gPGy__lTWNBcpi5Q8vBmobf6QK_YO-W7__WEbuajfdqSzWefgevzLmqj5-liYlA_plKLT-axuo7F_SfJn8Y3ii188qamE9cNOA-QyMtFyAd7XeG6ae-gIkQIwDpu81/s1600/programming_languages.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;130&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUWB5-XiiJ0aRCO5gPGy__lTWNBcpi5Q8vBmobf6QK_YO-W7__WEbuajfdqSzWefgevzLmqj5-liYlA_plKLT-axuo7F_SfJn8Y3ii188qamE9cNOA-QyMtFyAd7XeG6ae-gIkQIwDpu81/s400/programming_languages.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4154388125996283547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/07/tag-cloud-of-programming-languages.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4154388125996283547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4154388125996283547'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/07/tag-cloud-of-programming-languages.html' title='Tag Cloud of Programming Languages Based on Popularity'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUWB5-XiiJ0aRCO5gPGy__lTWNBcpi5Q8vBmobf6QK_YO-W7__WEbuajfdqSzWefgevzLmqj5-liYlA_plKLT-axuo7F_SfJn8Y3ii188qamE9cNOA-QyMtFyAd7XeG6ae-gIkQIwDpu81/s72-c/programming_languages.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-4859909755912455754</id><published>2011-04-03T10:58:00.000-07:00</published><updated>2011-04-03T10:58:10.404-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Chat"/><category scheme="http://www.blogger.com/atom/ns#" term="Facebook"/><category scheme="http://www.blogger.com/atom/ns#" term="Feed"/><category scheme="http://www.blogger.com/atom/ns#" term="Twitter"/><category scheme="http://www.blogger.com/atom/ns#" term="Windows"/><title type='text'>Best Combo for Facebook, Twitter, and Chat</title><content type='html'>As cool as TweetDeck is, have you ever looked at its privacy policy? yeck. many other similiar applications have similiar disclaimers in their privacy policies or ads all over the place. For windows users, there is a solution.&lt;br /&gt;
&lt;br /&gt;
For chat: Pidgin. Being open source, their&#39;s no ads and you&#39;re not selling your soul to use it. It works well, and with virtually any protocol (facebook, google, AIM, ...)&lt;br /&gt;
&lt;br /&gt;
For Twitter/Facebook/Digg/RSS/Etc. feeds: MahTweets. It is open source, using Microsoft&#39;s new Open Source license. Its interface is clean, it is customizable, and it is a CLIENT. it is not something you need to open your browser to use.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve been looking for a pair of applications like this for a while. I hope others find this useful.</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/4859909755912455754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/04/best-combo-for-facebook-twitter-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4859909755912455754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/4859909755912455754'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/04/best-combo-for-facebook-twitter-and.html' title='Best Combo for Facebook, Twitter, and Chat'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-7696044242638294037</id><published>2011-04-03T10:24:00.000-07:00</published><updated>2011-04-03T10:27:51.645-07:00</updated><title type='text'>Fuzzy Logic III: Proof Construction</title><content type='html'>&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;For those burning with questions on how to actually write a fuzzy logic proof. Even though the law of contradiction doesn&#39;t generally hold falor fuzzy logic, the normal rules of fuzzy logic do, with some extended functionality to deal with uncertainty.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;I will write about some of the basic rules of natural deduction here. from there, It should be readily seen how the rest of the rules follow.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;Before I move forward, it should be noted that last time, we worked with two different systems of logic: minimization (a &amp;amp; b = min(a,b)) and additive (a &amp;amp; b = max(0, x + y - 1) ) with negation being the operation (1-a) and with DeMorgan&#39;s Law adopted as an axiom.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;Since the things I am about to write about apply to &lt;i&gt;all&lt;/i&gt; fuzzy logics, I shall refer to the function which evaluates the certainty of a disjunction based on the certainties of the disjuncts as &lt;b&gt;d(x,y)&lt;/b&gt;. Therefore, for minimization logic, d(x,y) = max(x,y) (see previous post for more details). The same goes for the function which evaluates the certainty of a conjunct of, say, x and y based on the certainties of x and y themselves. Such a function (which evaluates the certainty of a conjunct) is here written as &lt;b&gt;c(x,y)&lt;/b&gt;.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Writing Convention &lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;In this document, I will format my proofs as follows:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;table style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;#&lt;/td&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp; assertion&lt;/td&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; certainty&lt;/td&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; justification&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;So therefore, with fuzzy logic proofs we deal with &lt;i&gt;three&lt;/i&gt; columns.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;As an example:&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;1. P&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 50%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;2. Q&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 80%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;3. R&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 30%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Conjunction&amp;nbsp; (Combination)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;In Fuzzy Logic, Conjunction (P , Q |= P &amp;amp; Q) works quite the same as conventional logic, with the extension that the attached conjunct is simply the same as c(x,y) for the logic with which we are dealing.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Example (taken from the example under &quot;Writing Convention&quot;:)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;1. P&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 50%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;2. Q &amp;nbsp; &amp;nbsp; 70% &amp;nbsp; &amp;nbsp; Premise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;3. P&amp;amp;Q &amp;nbsp; 50%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1,2, Conjunction (using minimization logic)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;===&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;3. p&amp;amp;Q&amp;nbsp;&amp;nbsp; 20%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1,2, Conjunction (using additive logic)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Disjunction (Addition)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;The same goes for dysjunction as for conjunction, namely, given p and q, p | q can be attached with the certainty given by d(p,q). P|Q above would therefore take on the values 70% and 100%, respectively.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2h5ip8K1Y_xNSQG_SFdlXH9jwGE7x5W8B3VWSG4kiMOiICQxtIJIKvQM0dZBE33lMITUneDKbuYM3C9NNRRZXYFCyq9PJVGsyGpLwJqeSInU-ogtEPMAzE_lBcu7CI6IgXlKaLllItp88/s1600/1.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;
&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;When adding any old proposition, say &lt;i&gt;p&lt;/i&gt;, one which we are not given the certainty value of, we write &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2h5ip8K1Y_xNSQG_SFdlXH9jwGE7x5W8B3VWSG4kiMOiICQxtIJIKvQM0dZBE33lMITUneDKbuYM3C9NNRRZXYFCyq9PJVGsyGpLwJqeSInU-ogtEPMAzE_lBcu7CI6IgXlKaLllItp88/s1600/1.gif&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2h5ip8K1Y_xNSQG_SFdlXH9jwGE7x5W8B3VWSG4kiMOiICQxtIJIKvQM0dZBE33lMITUneDKbuYM3C9NNRRZXYFCyq9PJVGsyGpLwJqeSInU-ogtEPMAzE_lBcu7CI6IgXlKaLllItp88/s1600/1.gif&quot; /&gt;&lt;/a&gt;, if the proposition to which one attaches &lt;i&gt;p&lt;/i&gt; has a certainty of 30%, for example.&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Modus Ponens&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0OLkCBVRuDLzenUmfPOXn9yTXRGKcS3vnMVBDJOLX7CPTV6yEM7hSuoMVlbgYZqR45yzGmHf40mbNuCLF6uTM-OkRZA1MORnYn9knQgVn4rZNvZnQoos2iGejyGDLXxz9S4i1bmISZXhq/s1600/2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;
&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLehZN9M5HF0gb-GzFrBUz-7goz55fkwfNWOqyGj_tbPAWEFrEz2VcJMFJBm2yVNC4xFOc1OxMkzgYQpyhef4AanDm_J9VMO1cZGYihrCulo8hHePTiwgX1JHlwD4lYym6innmlPL5lAnL/s1600/2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;
&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;As I said in my last post, we are not guarunteed the law of contradiction. In conventional logi c, it is sufficient to use Contradiction along with Conditional Exchange (&lt;/span&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLehZN9M5HF0gb-GzFrBUz-7goz55fkwfNWOqyGj_tbPAWEFrEz2VcJMFJBm2yVNC4xFOc1OxMkzgYQpyhef4AanDm_J9VMO1cZGYihrCulo8hHePTiwgX1JHlwD4lYym6innmlPL5lAnL/s1600/2.gif&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLehZN9M5HF0gb-GzFrBUz-7goz55fkwfNWOqyGj_tbPAWEFrEz2VcJMFJBm2yVNC4xFOc1OxMkzgYQpyhef4AanDm_J9VMO1cZGYihrCulo8hHePTiwgX1JHlwD4lYym6innmlPL5lAnL/s1600/2.gif&quot; /&gt;&lt;/a&gt;) and Conjunction to derive Modus Ponens. This is not the case in fuzzy logic; however, we can use the definition of d(x,y) and c(x,y) to make some significant inferences. In this example I will use additive logic, but it should easily be seen how to generalise this approach to any fuzzy logic.&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;We have:&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;1. P&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 43%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;2. P -&amp;gt; Q &amp;nbsp;&amp;nbsp; 83% &amp;nbsp; &amp;nbsp; Premise&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;And so we want to derive &lt;i&gt;Q&lt;/i&gt;. we plug P&#39;s certainty value in for the formula we use for computing the certainty of disjunction:&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;d((1-p),q) = .83&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;d((1-.43),q) = .83&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;We now substitute the particulars of &lt;i&gt;d(x,y)&lt;/i&gt;. In our case, this is &lt;i&gt;min(1,x+y)&lt;/i&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;min(1,1-.43+q) = .83&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;min(1,.57+q) = .83&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;It should be clear now that since &lt;i&gt;.83&lt;/i&gt; is less than &lt;i&gt;1&lt;/i&gt;, we know that &lt;i&gt;min(1,.57+q) = .57+q&lt;/i&gt;. And so&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;.57+q = .83&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp;q&amp;nbsp;&amp;nbsp;&amp;nbsp; = .26 .&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;We can now attach &lt;i&gt;Q&lt;/i&gt; to our proof above with certainty 26% under additive logic.&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;What if &lt;i&gt;P -&amp;gt; Q&lt;/i&gt;&#39;s value is 1 in this case? We find Q&#39;s certainty to be the least certainty that would give 1, adding &#39;greater than or equal to&#39; next to it:&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;P&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83%&amp;nbsp;&amp;nbsp;&amp;nbsp; Premise&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;2. P -&amp;gt; Q&amp;nbsp; 100%&amp;nbsp;&amp;nbsp; Premise&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;3. Q &amp;nbsp; &amp;nbsp; &amp;nbsp; 83%&amp;nbsp;&amp;nbsp;&amp;nbsp; min(1,.27+q) = 1 :. smallest q = .83 .&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;That&#39;s how it works: &lt;i&gt;we use the formulas for d(x,y) and what we know about the certainty of the conditional and the antecedent, we can derive the certainty of the consequent.&lt;/i&gt;&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Conditional Proof&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;How do we create conditionals? Easy. Simply assume p to some certainty, derive q to some certainty, and then infer p -&amp;gt; q and assign a certainty value of d(1-p,q).&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;For example, under minimisation logic:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp;1. P&amp;nbsp; 37%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assumption&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; .&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; .&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; .&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;17. Q&amp;nbsp; 75% &amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;some justification=&quot;&quot;&gt;&lt;/some&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;19. P -&amp;gt; Q&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 75%&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Contradiction&lt;span style=&quot;font-size: small;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Although the law of contradiction does not apply &lt;i&gt;in general&lt;/i&gt;, it applies at the &quot;end points&quot;. In other words, if one can derive &lt;i&gt;p&lt;/i&gt; with 100% certainty, and also &lt;i&gt;~q&lt;/i&gt; to 100% certainty, its conjuction will (by definition) have 100% certainty, and one can obtain 0% certainty (100% certainty of the negation) and use this and conditional proof to prove something via &lt;i&gt;reductio ad absurdum&lt;/i&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Conclusion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;This work was not intended as a comprehensive treatise on fuzzy logic inference rules, but hopefully I have provided in it a good feel for how it works. Enjoy! &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/7696044242638294037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/04/fuzzy-logic-iii-proof-construction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7696044242638294037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/7696044242638294037'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/04/fuzzy-logic-iii-proof-construction.html' title='Fuzzy Logic III: Proof Construction'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2h5ip8K1Y_xNSQG_SFdlXH9jwGE7x5W8B3VWSG4kiMOiICQxtIJIKvQM0dZBE33lMITUneDKbuYM3C9NNRRZXYFCyq9PJVGsyGpLwJqeSInU-ogtEPMAzE_lBcu7CI6IgXlKaLllItp88/s72-c/1.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-596520798949550404</id><published>2011-03-21T10:40:00.000-07:00</published><updated>2011-03-22T13:37:38.938-07:00</updated><title type='text'>Fuzzy Logic Proofs II: Systems of Logic</title><content type='html'>In this post I will discuss how fuzzy logic works as opposed to conventional logic.&amp;nbsp; This will lay groundwork for our discussion of fuzzy logic proofs later. Remember, the motivation for looking at such kinds of proofs is that it provides us with a means of dealing with uncertainty. Perhaps there are other motivations, but I will not mention them here.&lt;br /&gt;
&lt;br /&gt;
I assume basic knowledge of first order logic (and, or, not, only if, ...) and pretty much nothing else. Don&#39;t worry, I won&#39;t get all academic on you. We&#39;ll save that for papers and articles.&lt;br /&gt;
&lt;br /&gt;
Now there&#39;s a lot of theory and academic mumbo jumbo surrounding fuzzy logic, but practically speaking anyone can do it. A &quot;fuzzy logic system&quot; basically describes how to deal with &quot;a &amp;amp; b (a AND b)&quot;, &quot;a | b (a OR b)&quot;, and &quot;~a (NOT a)&quot; when we are, say, only 80% certain a is true and 50% certain b is true. There are two common ways of doing so that I will discuss here.&lt;br /&gt;
&lt;br /&gt;
Defining the last operation mentioned above is the easiest. no matter what kind of logic we use, &quot;~a&quot;, the logical complement of a, is always going to be &quot;1-a&quot;. This makes sense if look at conventional logic, taking 1 to be &quot;True&quot; and 0 to be &quot;False&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrDgp4JdXq_QWtRIn3rbnNjXUB9q-Ax_m7ZIZ80xUbooS2uGiuKf1z6CjoaybiBzirhLaR_3-FcQA5UdfmZBZR6xt-jvF3J9rUlBSqx54XI87BoCNhFY6HzAqv1Qkeog5mn71WOMdoWBpH/s1600/blog2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrDgp4JdXq_QWtRIn3rbnNjXUB9q-Ax_m7ZIZ80xUbooS2uGiuKf1z6CjoaybiBzirhLaR_3-FcQA5UdfmZBZR6xt-jvF3J9rUlBSqx54XI87BoCNhFY6HzAqv1Qkeog5mn71WOMdoWBpH/s1600/blog2.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Fuzzy Logic: Conservative Flavor&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The first is the most common. For &quot;a &amp;amp; b&quot;, where a=.5 (50% certain) and b=.8 (80% certain) it says this: &quot;Well, we know that a is 50% true, and b is more than 50% true, so we are at least 50% certain that the whole statement &#39;a &amp;amp; b&#39; is true.&quot; This conservative attitude contributes to its popularity, and the fact that we take the smallest certainty value to be the value of the whole statement gives it a name: &lt;i&gt;minimization&lt;/i&gt; fuzzy logic. So the certainty of the expression &quot;a &amp;amp; b&quot; is the smallest of the two between a and b. You may note that this works for conventional logic:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq41UmjRazQT0z1Klcej6jeq8baC53cHizzDmwiLVIZHoKYkHXHA23ADjbbr9WqVzZIVIub_f8zbwxDTOZ99eg1nLiV0AOKXzQm_Z9FxMcS8ThPYnXkOCXM_hKa_ddZ66fe25l7IgSoKY3/s1600/blog1.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq41UmjRazQT0z1Klcej6jeq8baC53cHizzDmwiLVIZHoKYkHXHA23ADjbbr9WqVzZIVIub_f8zbwxDTOZ99eg1nLiV0AOKXzQm_Z9FxMcS8ThPYnXkOCXM_hKa_ddZ66fe25l7IgSoKY3/s1600/blog1.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;as for &quot;a | b&quot;, we use DeMorgan&#39;s Law to define the meaning of disjunction. As &quot;a | b&quot; is equivalent to &quot;~(~a &amp;amp; ~b)&quot;, we can just use subtraction and &quot;min&quot; to find out our OR operation. It turns out that the certainty of the statement &quot;a | b&quot; turns out to be the greatest value between a and b. This matches our conservative intuition: &quot;We know a 50% true and b is 80% true, so &#39;a | b&#39; must be at least 80% true.&quot; This is again confirmed by using our conventional &quot;absolute truth&quot; model:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjsT-bcbejpMk4jqsGvkX8HNU0uYTfXHAFRXJVOeXx8NOL466RFwWZX0zYxaM-HpPuysxKDnZX-wgZsAlplB6c5qc5m76up5RX-U9pMfAZY7wsNe4BQJXfWVpjOFUAMYYpWqJ0_Qv5V5CA/s1600/blog3.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjsT-bcbejpMk4jqsGvkX8HNU0uYTfXHAFRXJVOeXx8NOL466RFwWZX0zYxaM-HpPuysxKDnZX-wgZsAlplB6c5qc5m76up5RX-U9pMfAZY7wsNe4BQJXfWVpjOFUAMYYpWqJ0_Qv5V5CA/s1600/blog3.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Furthermore, with this (and many other) systems of fuzzy logic, the conventional laws of association, commutation, and transititivity still apply, as well as our faithful friend, DeMorgan&#39;s Laws.&lt;br /&gt;
&lt;br /&gt;
Although not generally true of fuzzy logic (though totally true in conventional logic),&amp;nbsp;minimization&amp;nbsp;logic follows the law of idempotence; in other words, &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHekiBO739yh-ufXQHMlCmg2dl707naLbSDo-o4TRyvnE1hFqxindRN939_vJNf4qIabR9Ddy1o4NYbc_xpNlOJFVkXfTLewdArnDm6lGjEkxuTXUTeCoW6LWU7Wd_mjN2mOpDg6YS5TjD/s1600/blog4.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHekiBO739yh-ufXQHMlCmg2dl707naLbSDo-o4TRyvnE1hFqxindRN939_vJNf4qIabR9Ddy1o4NYbc_xpNlOJFVkXfTLewdArnDm6lGjEkxuTXUTeCoW6LWU7Wd_mjN2mOpDg6YS5TjD/s1600/blog4.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Fuzzy Logic: Liberal Flavor&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;No pun intended, by the way, in the naming of these flavors. They&#39;re both important for our purposes, and the usefulness and limits of each will be demonstrated.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;All the cool stuff except idempotence (association, commutation, transitivity, etc.) apply to this logic as well, including the fact &lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;that this kind of logic works with conventional logic (it works using only the values 0 and 1). &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;The next flavor of logic is actually defined, not by its conjunction operation (AND), but by its disjunction (OR). For example, let&#39;s say that we know x is 40% true and y is 30%. To figure out how to assign a certainty value to the phrase &#39;x | y&#39;, we simply add their certainties together; therefore, &#39;x | y&#39; has a certainty value of 70%.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;i&gt;Wait!&lt;/i&gt; &lt;i&gt;what if y was 70% certain? then &#39;x | y&#39; would be 110% certain!?!?&lt;/i&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;Nah. We&#39;ll just say that if the certainty of x and y sum to more than 1 (or just barely made it to one), the couple has &quot;made the cut&quot; and we say that their combined certainties are more than enough to make us certain that &#39;x | y&#39; is absolutely true. therefore, If the certainty of x and y are 40% and 80%, &#39;x | y&#39; is still 1. That&#39;s why this logic system is referred to as &lt;i&gt;bounded addition&lt;/i&gt;. We see that this flavor of logic is quite liberal - It takes the certainty of BOTH values into the value of the whole.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;Using DeMorgan&#39;s&amp;nbsp; Laws, we use NOT and OR to find AND.&amp;nbsp; Conjuction (AND) here has the same kind of &quot;make the cut&quot; attitude: &quot;If x and y&#39;s certainties sum to more than one, it&#39;s significant. Otherwise, we really can&#39;t say much about the certainty of &#39;x &amp;amp; y&#39; as a statement.&quot; In other words: take the certainties of x and y, subtract 1, and you have the value of &#39;x &amp;amp; y&#39;. Again the question arises, &quot;What if x and y are at 0%?&quot; The answer is in the same spirit as last time. if x+y-1 is less than 0, we&#39;ll just interpret that as we are so uncertain of x and y that we have more than enough reason simply to assign the certainty of truth for &#39;x &amp;amp; y&#39; to be false. &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;This is also called &lt;/span&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/%C5%81ukasiewicz_logic&quot;&gt;Łukasiewicz (Loo-KAH-she-vich) logic&lt;/a&gt;, after &lt;a href=&quot;http://en.wikipedia.org/wiki/Jan_%C5%81ukasiewicz&quot;&gt;the polish philosopher&lt;/a&gt; who first invented fuzzy logic. Yes, ladies and gentlemen - additive logic was the first fuzzy logic out there, invented near the turn of the 20th century.&lt;br /&gt;
&lt;br /&gt;
This logic is cool over other logics because unlike most other logics, Łukasiewicz logic obeys contradiction and excluded middle laws:&lt;br /&gt;
&quot;a &amp;amp; ~a&quot;=0%, &quot;a | ~a&quot;=100%. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;What? MOST fuzzy logic doesn&#39;t obey contradiction? How can people use minimization logic without it? How can MODUS PONENS even work without it?&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Oh, but it can. I&#39;ll show you how next time. (I said in my first post that I&#39;d save that stuff for my third post, not my second, but I think I&#39;ll just jump to the good stuff.)</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/596520798949550404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/03/fuzzy-logic-proofs-ii-systems-of-logic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/596520798949550404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/596520798949550404'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/03/fuzzy-logic-proofs-ii-systems-of-logic.html' title='Fuzzy Logic Proofs II: Systems of Logic'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrDgp4JdXq_QWtRIn3rbnNjXUB9q-Ax_m7ZIZ80xUbooS2uGiuKf1z6CjoaybiBzirhLaR_3-FcQA5UdfmZBZR6xt-jvF3J9rUlBSqx54XI87BoCNhFY6HzAqv1Qkeog5mn71WOMdoWBpH/s72-c/blog2.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4686393050407685865.post-3223754861413032106</id><published>2011-03-18T12:33:00.000-07:00</published><updated>2011-03-18T12:33:10.672-07:00</updated><title type='text'>Fuzzy Logical Proofs</title><content type='html'>Many decent EE Professors will tell you that Fuzzy Logic is used quite a bit in fuzzy control. For those of you who don&#39;t know what that is, congratulations; you&#39;re a member of normal society. We will not dwell on that here. Instead, we will focus these Fuzzy Logic energies into logical proofs.&lt;br /&gt;
&lt;br /&gt;
For those logicians out there familiar with normal two-column proofs, such as fitch-style natural deduction proofs or similiar, you will find this somewhat familiar. The difference between fuzzy proofs and conventional proofs is that fuzzy proofs provides us a mechanism to deal with uncertainty.&lt;br /&gt;
&lt;br /&gt;
In conventional First Order Logic, we may for any given statement assign a truth value out of the set of two truth values, True and False. In Fuzzy Logic, there is a &quot;spectrum of truth&quot; wherein a statement can be &quot;20% True&quot; and &quot;80% False&quot;. Another (more intuitionistic) interpretation of such a value in terms of using it to form a proof is that we are 20% certain that value A is true. Thus fuzzy proofs allow us to use premises with varying degrees of certainty, and in a chosen interpretation allow us to prove results, perhaps even with higher degrees of certainty than our premises. (Side note: those of you familiar with Zadeh&#39;s work may cringe at this, but I will explain what I mean when we get there.)&lt;br /&gt;
&lt;br /&gt;
This post starts a series of blog posts which I will publish on the subject of Fuzzy Proofs as I understand them. Please feel free to make comments and give criticisms for my arguments. &lt;br /&gt;
&lt;br /&gt;
In the first post we will define what &quot;fuzzy logic&quot; herein means, and explore the possibilities of the different logical systems at our disposal, and why we may or may not choose them for our proof or to solve a specific problem. Feedback will be requested here. This is a domain which I am trying to understand better even now.&lt;br /&gt;
&lt;br /&gt;
In the second post we will define what an &quot;interpretation&quot; is, or in other words, we will define how to translate our mathy proof back into english so that it may be used to make decisions, as all useful proofs must ultimately provide use for this end.&lt;br /&gt;
&lt;br /&gt;
In the last post, we will walk through a sample fuzzy logic proof. I will comment on its usefulness, its form, and its weaknesses.&lt;br /&gt;
&lt;br /&gt;
From what I can understand, this field has only been explored by few scholars, most deeming it of little use. But I find it relevant here to examine G. H. Hardy, who said &quot;I have never done anything useful,&quot; thinking number theory to be an unimportant part of mathematics. Without him, RSA would not be where it is today. (re-quoted from &lt;i&gt;Algorithms,&lt;/i&gt; by S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani, p. 41.)</content><link rel='replies' type='application/atom+xml' href='http://djhaskin987.blogspot.com/feeds/3223754861413032106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://djhaskin987.blogspot.com/2011/03/fuzzy-logical-proofs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/3223754861413032106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4686393050407685865/posts/default/3223754861413032106'/><link rel='alternate' type='text/html' href='http://djhaskin987.blogspot.com/2011/03/fuzzy-logical-proofs.html' title='Fuzzy Logical Proofs'/><author><name>Scruff McGruff</name><uri>http://www.blogger.com/profile/10045047004997974500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEra-HfHwCp4kP5ZsqrVkQ3O-vgRM84Ybwi-YqkFzQ2gdaGoWgS0rFA-P8VZpJKLHTueI0KJCsD5yYBhCTppSEMxVM85s3AqRhVbGNeQoJx4L_xAXGEnjMipuDNBkPudZ90v4GRg-SZzu04kosz-z43r5mXN_lKi51BTciIPTZIa16vg/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry></feed>