{"id":1650,"date":"2019-07-21T20:51:07","date_gmt":"2019-07-21T15:21:07","guid":{"rendered":"https:\/\/www.rangakrish.com\/?p=1650"},"modified":"2019-07-21T20:51:07","modified_gmt":"2019-07-21T15:21:07","slug":"custom-text-analysis-using-textrazors-prolog-engine","status":"publish","type":"post","link":"https:\/\/www.rangakrish.com\/index.php\/2019\/07\/21\/custom-text-analysis-using-textrazors-prolog-engine\/","title":{"rendered":"Custom Text Analysis Using TextRazor\u2019s Prolog Engine"},"content":{"rendered":"<p>This is the third part in the series on <em><strong>information extraction<\/strong><\/em> from unstructured text. In the <a href=\"https:\/\/www.rangakrish.com\/index.php\/2019\/06\/24\/text-analysis-using-meaningclouds-deep-categorization-api\/\" target=\"_blank\" rel=\"noopener\"><em><strong>first part<\/strong><\/em><\/a>, we saw how <a href=\"https:\/\/www.meaningcloud.com\" target=\"_blank\" rel=\"noopener\"><em><strong>MeaningCloud<\/strong><\/em><\/a>\u00a0allows us to specify complex rules to identify custom categories through their <em><strong>Deep Categorization<\/strong><\/em> API. The <a href=\"https:\/\/www.rangakrish.com\/index.php\/2019\/07\/11\/information-extraction-using-spacys-pattern-matcher\/\" target=\"_blank\" rel=\"noopener\"><em><strong>second part<\/strong><\/em><\/a>\u00a0covered <a href=\"https:\/\/spacy.io\" target=\"_blank\" rel=\"noopener\"><em><strong>spaCy\u2019s<\/strong><\/em><\/a>\u00a0pattern matcher.<\/p>\n<p>Today, I would like to discuss how we can use <a href=\"https:\/\/www.textrazor.com\" target=\"_blank\" rel=\"noopener\"><em><strong>TextRazor\u2019s<\/strong><\/em><\/a>\u00a0<em><strong>\u201cProlog Engine\u201d<\/strong><\/em> to perform customized text analysis.<span class=\"Apple-converted-space\">\u00a0<\/span><\/p>\n<p><em><strong>TextRazor<\/strong><\/em> provides a powerful API for dealing with natural language text. It supports <em><strong>Classification<\/strong><\/em>, <em><strong>Topic Tagging<\/strong><\/em>, <em><strong>Entity Recognition<\/strong><\/em>, <em><strong>Dependency Parsing<\/strong><\/em>, and more. What makes <em><strong>TextRazor<\/strong><\/em> somewhat unique is the ability to seamlessly attach <a href=\"https:\/\/www.textrazor.com\/rules\" target=\"_blank\" rel=\"noopener\"><em><strong>custom rules<\/strong><\/em><\/a>\u00a0written in <em><strong>Prolog<\/strong><\/em> in order to discover special patterns in the text. These rules can make use of the rich set of built-in predicates that expose the core logic of the NLP engine.<\/p>\n<p>The prolog engine in <em><strong>TextRazor<\/strong><\/em> is based on the popular <a href=\"https:\/\/www.swi-prolog.org\" target=\"_blank\" rel=\"noopener\"><em><strong>SWI Prolog<\/strong><\/em><\/a>\u00a0implementation (<em><strong>TextRazor\u2019s<\/strong><\/em> documentation incorrectly mentions this as <em><strong>YAP<\/strong><\/em> prolog).<\/p>\n<p>Since <em><strong>Prolog<\/strong><\/em> is a full-fledged programming language (albeit quite different from the <em><strong>\u201cconventional\u201d<\/strong><\/em> languages), the ability to write custom logic in <em><strong>Prolog<\/strong><\/em> implies that we can encode arbitrarily complex logic in order to discover interesting patterns in text.<\/p>\n<p>I have written a <em><strong>REST<\/strong><\/em> client in <em><strong>Lisp<\/strong><\/em> that shows how to use <em><strong>Prolog<\/strong><\/em> rules to extract key pieces of information about a patient coming to the doctor for consultation. For practical reasons, the program and the case description are deliberately kept simple in order to focus on the idea.<\/p>\n<p>Let us consider the following case text:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">Mr.John Haggard, aged 30 years, has cold and cough. He sneezes when exposed to <\/span><br \/>\n<span style=\"color: #0000ff;\">cold weather. There is headache on waking up. He has runny nose as well.<\/span><\/p><\/blockquote>\n<p>Given this text, we want to extract the <em><strong>Name<\/strong><\/em>, <em><strong>Gender<\/strong><\/em> and <em><strong>Age<\/strong><\/em> of the patient. In addition, (as in the previous two articles) we want to know if the patient is suffering from <em><strong>\u201ccommon-cold\u201d<\/strong><\/em> or <em><strong>\u201cdiarrhea\u201d.<\/strong><\/em> Here is the set of <em><strong>Prolog<\/strong><\/em> rules that will do the job:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">common_cold :- sequence(&#8216;runny&#8217;, &#8216;nose&#8217;).<\/span><br \/>\n<span style=\"color: #0000ff;\">common_cold :- lemma(S), member(S, [&#8216;headache&#8217;, &#8216;cold&#8217;, &#8216;cough&#8217;, &#8216;sneeze&#8217;]).<\/span><br \/>\n<span style=\"color: #0000ff;\">diarrhea :- lemma(&#8216;loose&#8217;), or( lemma(&#8216;motion&#8217;), lemma(&#8216;stools&#8217;)).<\/span><br \/>\n<span style=\"color: #0000ff;\">diarrhea :- lemma(&#8216;diarrhoea&#8217;); lemma(&#8216;diarrhea&#8217;).<\/span><br \/>\n<span style=\"color: #0000ff;\">name(N) :- sequence(lemma(X), token(TID1, N1), token(TID2, N2)), title(X),<\/span><br \/>\n<span style=\"color: #0000ff;\">part_of_speech(TID1, &#8216;NNP&#8217;), part_of_speech(TID2, &#8216;NNP&#8217;), N = [N1, N2],!.<\/span><br \/>\n<span style=\"color: #0000ff;\">name(N) :- sequence(lemma(X), token(TID, N)), title(X), part_of_speech(TID, &#8216;NNP&#8217;).<\/span><br \/>\n<span style=\"color: #0000ff;\">title(X) :- member(X, [&#8216;mr.&#8217;, &#8216;mrs.&#8217;, &#8216;miss.&#8217;, &#8216;ms.&#8217;]).<\/span><br \/>\n<span style=\"color: #0000ff;\">gender(G) :- lemma(X), member(X, [&#8216;he&#8217;, &#8216;his&#8217;, &#8216;him&#8217;]), G = &#8216;male&#8217;.<\/span><br \/>\n<span style=\"color: #0000ff;\">gender(G) :- lemma(X), member(X, [&#8216;she&#8217;, &#8216;her&#8217;]), G = &#8216;female&#8217;.<\/span><br \/>\n<span style=\"color: #0000ff;\">is_number(Str) :- atom_string(Atom, Str), atom_number(Atom, _).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(token(X), &#8216;years&#8217;, &#8216;old&#8217;), is_number(X).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(&#8216;aged&#8217;, token(X), &#8216;years&#8217;), is_number(X).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(token(X), &#8216;years&#8217;, &#8216;of&#8217;, &#8216;age&#8217;), is_number(X).<\/span><\/p><\/blockquote>\n<p>The predicate <em><strong>common-cold<\/strong><\/em> will be <em><strong>True<\/strong><\/em> if the text contains the sequence of words <strong>\u201crunny\u201d<\/strong> and <strong>\u201cnose\u201d<\/strong> (without any other intervening word), or if the text contains the root form (<em><strong>\u201clemma\u201d<\/strong><\/em>) of any of the words <strong>\u201cheadache\u201d<\/strong>, <strong>\u201ccold\u201d<\/strong>, <strong>\u201ccough\u201d<\/strong>, and <strong>\u201csneeze\u201d<\/strong>.<\/p>\n<p>Likewise, we can infer that the patient has <em><strong>diarrhea<\/strong><\/em>\u00a0if the word <strong>\u201cdiarrhea\u201d<\/strong> (or <strong>\u201cdiarrhoea\u201d<\/strong>) occurs directly in the text, or we have either <strong>\u201cloose motion\u201d<\/strong> or <strong>\u201cloose stools\u201d<\/strong>.<span class=\"Apple-converted-space\">\u00a0<\/span><\/p>\n<p>To determine the <em><strong>Name<\/strong><\/em> of the patient, we first look for the <em><strong>Title<\/strong><\/em>\u00a0(i.e., how we address the person) &#8211; <strong>\u201cMr.\u201d, \u201cMrs.\u201d, \u201cMs\u201d, <\/strong>or<strong> \u201cMiss.\u201d,<\/strong> followed by one or two <em><strong>Proper Nouns<\/strong><\/em>. Although this itself can give a clue to the gender of the person, I am defining a separate predicate for this. The gender is <em><strong>male<\/strong><\/em> if any of the words <strong>&#8220;he&#8221;, &#8220;him&#8221;, <\/strong>or<strong> &#8220;his&#8221;<\/strong> occurs in the text. Similarly, the gender is <em><strong>female<\/strong><\/em> if either <strong>&#8220;she&#8221;<\/strong> or <strong>&#8220;her&#8221;<\/strong> is present in the text.<\/p>\n<p>The <em><strong>age<\/strong><\/em> of the patient is also determined from the context. It is a number conforming to any of the following patterns:<\/p>\n<ul>\n<li><span style=\"color: #0000ff;\">&lt;Age&gt; \u201cyears\u201d \u201cold\u201d ( =&gt; \u201c40 years old\u201d)<\/span><\/li>\n<li><span style=\"color: #0000ff;\">\u201caged\u201d &lt;Age&gt; \u201cyears ( =&gt; \u201caged 40 years\u201d)<\/span><\/li>\n<li><span style=\"color: #0000ff;\">&lt;Age&gt; \u201cyears\u201d \u201cof\u201d \u201cage\u201d ( =&gt; \u201c40 years of age\u201d)<\/span><\/li>\n<\/ul>\n<p>Obviously, I have simplified the rules to make it easier to understand the logic and the approach.<span class=\"Apple-converted-space\">\u00a0<\/span><\/p>\n<p><em><strong>TextRazor<\/strong><\/em> API requires that when we pass the <em><strong>Prolog<\/strong><\/em> rules to the NLP engine, we have to additionally mention the specific <em><strong>\u201cextractors\u201d<\/strong> <\/em>(in our case, the <em>predicates<\/em>) that it should try to satisfy. For this example, the extractors is a list of <em><strong>\u201ccommon-cold\u201d, \u201cdiarrhea\u201d, \u201cname\u201d, \u201cgender\u201d, <\/strong><\/em>and<em><strong> \u201cage\u201d<\/strong><\/em> (you will understand better when you see the <em><strong>Lisp<\/strong><\/em> code). Notice that I am not passing <em><strong>\u201ctitle\u201d<\/strong><\/em>, although it is a predicate in my rule set. The reason is that I am not specifically looking for <em><strong>\u201ctitle\u201d<\/strong><\/em> as an expected output; it is just an <em><strong>auxiliary predicate<\/strong><\/em> used in another main predicate called <em><strong>\u201cname\u201d<\/strong><\/em>.<\/p>\n<p>If you have followed the <em><strong>Prolog<\/strong><\/em> code carefully, you might notice a limitation in my approach. For each ailment I am looking for, I will have to define a predicate such as <em><strong>\u201cfever\u201d, \u201casthma\u201d, \u201cdementia\u201d,<\/strong><\/em> etc., and additionally, <em>include<\/em> that predicate name in the list of <em>extractors<\/em>. Not impossible, but not quite elegant!<\/p>\n<p>What is the alternative? Instead of defining a predicate matching the name of the ailment (or in addition to that), we can follow this strategy:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">ailment(NameOfAilment) :- &lt;Bind argument to the actual ailment&gt;<\/span><\/p><\/blockquote>\n<p>For example,<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">ailment(Name) :- common_cold, Name = \u2018common-cold\u2019.<\/span><\/p>\n<p><span style=\"color: #0000ff;\">ailment(Name) :- diarrhea, Name = \u2018diarrhea\u2019.<\/span><\/p><\/blockquote>\n<p>And so on\u2026 In this case, if <em><strong>common-cold<\/strong><\/em> is <em><strong>True<\/strong><\/em>, the <em><strong>Name<\/strong><\/em> argument of <em><strong>ailment<\/strong><\/em> predicate is set to <em><strong>common-cold<\/strong><\/em>, and likewise for <em><strong>diarrhea<\/strong><\/em>.<\/p>\n<p>In fact, we can do better:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">ailment(common_cold) :- common_cold.<\/span><\/p>\n<p><span style=\"color: #0000ff;\">ailment(diarrhea) :- diarrhea.<\/span><\/p><\/blockquote>\n<p>Now we don\u2019t have to include the individual ailment predicates in our extractors list; we only have to include <em><strong>\u201cailment\u201d<\/strong><\/em>. Here is the updated rules:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">common_cold :- sequence(&#8216;runny&#8217;, &#8216;nose&#8217;).<\/span><br \/>\n<span style=\"color: #0000ff;\">common_cold :- lemma(S), member(S, [&#8216;headache&#8217;, &#8216;cold&#8217;, &#8216;cough&#8217;, &#8216;sneeze&#8217;]).<\/span><br \/>\n<span style=\"color: #0000ff;\">diarrhea :- lemma(&#8216;loose&#8217;), or( lemma(&#8216;motion&#8217;), lemma(&#8216;stools&#8217;)).<\/span><br \/>\n<span style=\"color: #0000ff;\">diarrhea :- lemma(&#8216;diarrhoea&#8217;); lemma(&#8216;diarrhea&#8217;).<\/span><br \/>\n<strong><span style=\"color: #0000ff;\">ailment(common_cold) :- common_cold.<\/span><\/strong><br \/>\n<strong><span style=\"color: #0000ff;\">ailment(diarrhea) :- diarrhea.<\/span><\/strong><br \/>\n<span style=\"color: #0000ff;\">name(N) :- sequence(lemma(X), token(TID1, N1), token(TID2, N2)), title(X),<\/span><br \/>\n<span style=\"color: #0000ff;\">part_of_speech(TID1, &#8216;NNP&#8217;), part_of_speech(TID2, &#8216;NNP&#8217;), N = [N1, N2],!.<\/span><br \/>\n<span style=\"color: #0000ff;\">name(N) :- sequence(lemma(X), token(TID, N)), title(X), part_of_speech(TID, &#8216;NNP&#8217;).<\/span><br \/>\n<span style=\"color: #0000ff;\">title(X) :- member(X, [&#8216;mr.&#8217;, &#8216;mrs.&#8217;, &#8216;miss.&#8217;, &#8216;ms.&#8217;]).<\/span><br \/>\n<span style=\"color: #0000ff;\">gender(G) :- lemma(X), member(X, [&#8216;he&#8217;, &#8216;his&#8217;, &#8216;him&#8217;]), G = &#8216;male&#8217;.<\/span><br \/>\n<span style=\"color: #0000ff;\">gender(G) :- lemma(X), member(X, [&#8216;she&#8217;, &#8216;her&#8217;]), G = &#8216;female&#8217;.<\/span><br \/>\n<span style=\"color: #0000ff;\">is_number(Str) :- atom_string(Atom, Str), atom_number(Atom, _).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(token(X), &#8216;years&#8217;, &#8216;old&#8217;), is_number(X).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(&#8216;aged&#8217;, token(X), &#8216;years&#8217;), is_number(X).<\/span><br \/>\n<span style=\"color: #0000ff;\">age(X) :- sequence(token(X), &#8216;years&#8217;, &#8216;of&#8217;, &#8216;age&#8217;), is_number(X).<\/span><\/p><\/blockquote>\n<p>Note the highlighted predicates. This is a matter of design choice, and I prefer the latter.<\/p>\n<p>The program is tested on three inputs:<\/p>\n<blockquote><p><span style=\"color: #0000ff;\">(setf *text1*<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;Mr.John Haggard, aged 30 years, has cold and cough. He sneezes when exposed to <\/span><br \/>\n<span style=\"color: #0000ff;\">cold weather. There is headache on waking up. He has runny nose as well.<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;)<\/span><\/p>\n<p><span style=\"color: #0000ff;\">(setf *text2*<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;Ms.Mary, who is 40 years old, came to the clinic with complaint of loose motion. <\/span><br \/>\n<span style=\"color: #0000ff;\">She said the problem started two days ago after she ate some fruits.<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;)<\/span><\/p>\n<p><span style=\"color: #0000ff;\">(setf *text3*<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;Mrs.Anne Lovelord, aged 60 years, complains of cold with incessant sneezing. <\/span><br \/>\n<span style=\"color: #0000ff;\">She passes loose motion twice a day.<\/span><br \/>\n<span style=\"color: #0000ff;\">&#8220;)<\/span><\/p><\/blockquote>\n<p>Here is the actual output from the Lisp program:<\/p>\n<figure id=\"attachment_1653\" aria-describedby=\"caption-attachment-1653\" style=\"width: 650px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg?ssl=1\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" data-attachment-id=\"1653\" data-permalink=\"https:\/\/www.rangakrish.com\/index.php\/2019\/07\/21\/custom-text-analysis-using-textrazors-prolog-engine\/output-3\/\" data-orig-file=\"https:\/\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg\" data-orig-size=\"769,271\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;Admin&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1563734780&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Result of Processed Case\" data-image-description=\"&lt;p&gt;Result of Processed Case&lt;\/p&gt;\n\" data-image-caption=\"&lt;p&gt;Result of Processed Case&lt;\/p&gt;\n\" data-large-file=\"https:\/\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg\" class=\"wp-image-1653\" src=\"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg?resize=650%2C229&#038;ssl=1\" alt=\"Result of Processed Case\" width=\"650\" height=\"229\" srcset=\"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg?w=769&amp;ssl=1 769w, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg?resize=300%2C106&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/07\/Output-1.jpg?resize=768%2C271&amp;ssl=1 768w\" sizes=\"(max-width: 650px) 100vw, 650px\" \/><\/a><figcaption id=\"caption-attachment-1653\" class=\"wp-caption-text\"><strong>Result of Processed Case<\/strong><\/figcaption><\/figure>\n<p>I hope you can see the power of defining custom logic in such an expressive language as <em><strong>Prolog<\/strong><\/em>. It allows you to do almost anything you want. Of course, if you are not careful, you can end up adversely affecting the performance of the system. (I hope that <em><strong>TextRazor<\/strong><\/em> has built in adequate safeguards against malware masquerading as custom rules!)<\/p>\n<p>At this juncture, I want to point out a practical issue.<span class=\"Apple-converted-space\">\u00a0 <\/span>Although I am comfortable programming in\u00a0<em><strong>Prolog<\/strong><\/em>, I found the experience of developing and testing the rules a bit difficult and tedious. The only way to test the logic is to experiment by writing a client program like I did. I wish there was some kind of <em><strong>\u201cDeveloper Console\u201d<\/strong><\/em> or <em><strong>\u201cTest Console\u201d<\/strong><\/em>, where I can quickly enter my <em><strong>Prolog<\/strong><\/em> rules, give a sample piece of text and check the result. In the case of <em><strong>MeaningCloud<\/strong><\/em>, the <em><strong>\u201cTest Console\u201d<\/strong><\/em> was quite helpful and we didn\u2019t have to write any client code to test the logic. Although <em><strong>TextRazor&#8217;s<\/strong><\/em> site has a <a href=\"https:\/\/www.textrazor.com\/demo\" target=\"_blank\" rel=\"noopener\"><em><strong>&#8220;Demo&#8221;<\/strong><\/em><\/a> mode, it does not support defining <em><strong>Prolog<\/strong><\/em> rules and custom extractors. I hope <em><strong>TextRazor<\/strong><\/em> addresses this limitation in the near future. Despite this minor limitation, the overall approach of supporting <em><strong>Prolog<\/strong><\/em> logic engine is highly commendable!<\/p>\n<p>You can download my <em><strong>Lisp<\/strong><\/em> code <a href=\"http:\/\/www.rangakrish.com\/downloads\/TextRazor-Rules.lisp\" target=\"_blank\" rel=\"noopener\"><em><strong>here<\/strong><\/em><\/a>. The program has been tested in <a href=\"http:\/\/www.lispworks.com\" target=\"_blank\" rel=\"noopener\"><em><strong>LispWorks<\/strong><\/em><\/a>.<\/p>\n<p>Have a great weekend!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the third part in the series on information extraction from unstructured text. In the first part, we saw how MeaningCloud\u00a0allows us to specify complex rules to identify custom categories through their Deep Categorization API. The second part\u00a0covered spaCy\u2019s\u00a0pattern matcher. Today, I would like to discuss how we can use TextRazor\u2019s\u00a0\u201cProlog Engine\u201d to perform [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[18,107,17,147],"tags":[212,194,45],"class_list":["post-1650","post","type-post","status-publish","format-standard","hentry","category-lisp","category-natural-language-processing","category-programming","category-prolog","tag-information-extraction","tag-text-analysis","tag-textrazor"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9OLnF-qC","jetpack-related-posts":[{"id":1817,"url":"https:\/\/www.rangakrish.com\/index.php\/2019\/12\/08\/using-definite-clause-grammars-dcg-for-information-extraction\/","url_meta":{"origin":1650,"position":0},"title":"Using Definite Clause Grammars (DCG) for Information Extraction","author":"admin","date":"December 8, 2019","format":false,"excerpt":"In the previous article, I showed how we can use ATNs for extracting key information from natural language text. I also pointed out in that article that Definite Clause Grammars (DCG) are a more compact formalism for doing this. That will be the focus of today's article. For a nice\u2026","rel":"","context":"In &quot;Natural Language Processing&quot;","block_context":{"text":"Natural Language Processing","link":"https:\/\/www.rangakrish.com\/index.php\/category\/natural-language-processing\/"},"img":{"alt_text":"Processing the Text","src":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/12\/Processing-file-code.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/12\/Processing-file-code.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/12\/Processing-file-code.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1025,"url":"https:\/\/www.rangakrish.com\/index.php\/2018\/08\/19\/sicstus-prolog-building-a-windows-executable\/","url_meta":{"origin":1650,"position":1},"title":"Sicstus Prolog &#8211; Building a Windows Executable","author":"admin","date":"August 19, 2018","format":false,"excerpt":"In my previous post, I showed how to build a C-based Windows DLL to execute Prolog predicates in the Sicstus Prolog\u00a0engine. Today, I want to show how to build an executable (on Windows) from a C\/C++ program that uses Sicstus prolog engine. The process is quite simple. In order to\u2026","rel":"","context":"In &quot;Natural Language Processing&quot;","block_context":{"text":"Natural Language Processing","link":"https:\/\/www.rangakrish.com\/index.php\/category\/natural-language-processing\/"},"img":{"alt_text":"Creating WordNet Prolog Image","src":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Creating-image.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Creating-image.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Creating-image.png?resize=525%2C300 1.5x"},"classes":[]},{"id":2922,"url":"https:\/\/www.rangakrish.com\/index.php\/2022\/10\/06\/why-learn-prolog\/","url_meta":{"origin":1650,"position":2},"title":"Why Learn Prolog?","author":"admin","date":"October 6, 2022","format":false,"excerpt":"There are several programming languages in use today and a simple google search will throw up interesting recommendations of a subset of these languages to learn, usually based on popularity ranking. As is expected, the popularity of a programming language varies over time and hence a language that was in\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.rangakrish.com\/index.php\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2804,"url":"https:\/\/www.rangakrish.com\/index.php\/2022\/05\/15\/students-assessment-advisor-in-prolog\/","url_meta":{"origin":1650,"position":3},"title":"Students Assessment Advisor in Prolog","author":"admin","date":"May 15, 2022","format":false,"excerpt":"A close relative of mine teaches Maths to school students in different Grades. During a casual chat some time ago, he mentioned that he was trying to adopt an automated approach to selecting assignment problems based on each student's performance so far. Obviously, there are many ways in which this\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.rangakrish.com\/index.php\/category\/programming\/"},"img":{"alt_text":"Concept Dependencies","src":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2022\/05\/Concept-Dependencies-300x128.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2022\/05\/Concept-Dependencies-300x128.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2022\/05\/Concept-Dependencies-300x128.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1757,"url":"https:\/\/www.rangakrish.com\/index.php\/2019\/10\/13\/conjugating-phrasal-verbs\/","url_meta":{"origin":1650,"position":4},"title":"Conjugating Phrasal Verbs","author":"admin","date":"October 13, 2019","format":false,"excerpt":"In the last article, I showed how to generate verb conjugations in the \"iLexicon\" system. Today, let us see how this idea can be extended to English \"phrasal verbs\". According to Wikipedia: \"a phrasal verb is a phrase such as turn down or ran into which combines two or three\u2026","rel":"","context":"In &quot;Natural Language Processing&quot;","block_context":{"text":"Natural Language Processing","link":"https:\/\/www.rangakrish.com\/index.php\/category\/natural-language-processing\/"},"img":{"alt_text":"Conjugation of \"Turn on\"","src":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2019\/10\/Example3.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1004,"url":"https:\/\/www.rangakrish.com\/index.php\/2018\/08\/05\/sicstus-prolog-building-a-windows-dll\/","url_meta":{"origin":1650,"position":5},"title":"Sicstus Prolog &#8211; Building a Windows DLL","author":"admin","date":"August 5, 2018","format":false,"excerpt":"Last week I upgraded to the latest version (4.4.1) of Sicstus Prolog\u00a0for Windows.\u00a0Since the Prolog engine can be embedded (royalty free) in other applications, it is useful to understand how to create a DLL (on Windows) for this purpose. In today's article, I would like to outline this process in\u2026","rel":"","context":"In &quot;C++&quot;","block_context":{"text":"C++","link":"https:\/\/www.rangakrish.com\/index.php\/category\/c\/"},"img":{"alt_text":"Creating Prolog Program Image","src":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Saving-Prolog-Image.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Saving-Prolog-Image.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.rangakrish.com\/wp-content\/uploads\/2018\/08\/Saving-Prolog-Image.png?resize=525%2C300 1.5x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/posts\/1650","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/comments?post=1650"}],"version-history":[{"count":0,"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/posts\/1650\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/media?parent=1650"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/categories?post=1650"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rangakrish.com\/index.php\/wp-json\/wp\/v2\/tags?post=1650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}