Comparing PROLOG input to facts - prolog

Say I have a list of PROLOG facts, which are Blog Post titles, the author, and the year they were written:
blogpost('Title 1', 'author1' 2012).
blogpost('Title 2', 'author1', 2011).
blogpost('Title 3', 'author1' 2010).
blogpost('Title 4', 'author1', 2006).
blogpost('Title 5', 'author2' 2009).
blogpost('Title 6', 'author2', 2011).
I want to write a rule which has two parameters/inputs, the author, and the year. If the author entered has written an article after the specified year, PROLOG would return true.
Here is what I have tried:
authoredAfter(X,Z) :-
blogpost(_,X,Z),
So if I queried ?- authoredAfter('author1',2010). PROLOG would return true because the Author has written an article in 2010. However, if I query ?- authoredAfter('author1',2009)., it would return false, but I want it to return true because author1 has written an article after that year.
My question is, how do I compare the user input value to the value in the fact?

You need two use two distinct variables for the year of the article and for the year you want to start your search from and compare them. Something like this:
authoredAfter(Author, Year1):-
blogpost(_, Author, Year2),
Year2 >= Year1.
You express the fact that Author authoredAfter Year1 if there is a blog post written by Author in Year2 and Year2 >= Year1.
If you issue a query to see if author1 wrote anything after 2009:
?- authoredAfter(author1, 2009).
true ;
true ;
true ;
false.
the goal is satisfied three times as author1 has 3 blog posts after 2009 (2010, 2011, 2012). If you want to get a single answer, no matter how many such articles exist, you can use once/1:
authoredAfter(Author, Year1):-
once((blogpost(_, Author, Year2),
Year2 >= Year1)).
?- authoredAfter(author1, 2009).
true.

Related

Laravel QueryBuilder multiple columns match in the same WhereIn

I would have liked to convert a SQL query like this one in Laravel Eloquent.
This query works on MariaDb but i don't know about other engines (might be the reason why it isn't implented):
id
year
country
enabled
0
2000
"France"
0
1
2001
"Spain"
0
2
2002
"France"
1
3
2003
"Germany"
1
SELECT id FROM my_db.countries WHERE (name, enabled) IN (("France", 1), ("Spain", 0));
This returns 1 and 2.
This is possible with Eloquent (as suggested here: laravel whereIn multiple columns but it wouldn't return the expected results:
DB::table('countries')->select('id')->whereIn('name', ["france", "Spain"])->whereIn('enabled', [0, 1])->all();
This returns 0, 1 and 2.
I gave a shot at adapting the Illuminate/Database library to fit my needs but the databinding started to get really complexe.
I managed to make it with a whereRaw query but it isn't really clean enough for production code as there are no data binding (values shows up with ->toSql()).
Does anyone have an idea?
The query syntax you want to get:
SELECT id FROM my_db.countries WHERE (name, enabled) IN (("France", 1), ("Spain", 0));
is exclusive to Oracle. The whereIn method of Laravel supports (String, Array), so I think you only have the options to do it through raw queries or using the solution proposed by V-K
I suppose you wanna get records that satisfy two conditions. whereIn checks if the column contains one of the values in the array.
`DB::table('countries')->select('id')->whereIn('name', ["france", "Spain"])->whereIn('enabled', [0, 1])->all();`
that code returns combinations france 0, france 1, Spain 0, Spain 1.
TO get combinations france 0 and Spain 1 you can use this code
DB::table('countries')
->select('id')
->where(function(Builder $builder) {
$builder
->where('name', 'france')
->where('enabled', 0);
})
->orWhere(function(Builder $builder) {
$builder
->where('name', 'Spain')
->where('enabled', 1);
})
->get();
It checks the conditions name = france and enabled = 0 work together
If you add a new column that will keep the concatenation of the country and enabled fields, then you can use a simple whereIn method.
id
year
country
enabled
country_enabled
0
2000
"France"
0
"France-0"
1
2001
"Spain"
0
"Spain-0"
2
2002
"France"
1
"France-1"
3
2003
"Germany"
1
"Germany-1"
DB::table('countries')->select('id')->whereIn('country_enabled ', ["France-1", "Spain-0"])->get();
You may even add an index to that column to speed up the search.
Of course, the provided solution will add some slight overhead to the writing in that table.

associated the list in the on pressed method

enter image description herewhen i try to make an if statment in the on Pressed an error occured which is => 'Equality operator '==' invocation with references of unrelated typesthis is my code and in the text you will see my list i want to make an if statment in onPressed method
final List<Movie> movies = [
Movie(
imageUrl: 'assets/images/5s.PNG',
title: 'video 1',
categories: 'Fantasy, Sci-fi',
year: 2018,
country: 'uk',
length: 60,
description:
'Our friendly neighborhood Super Hero decides to join his best friends Ned, MJ, and the rest of the gang on a European vacation. However, Peter\'s plan to leave super heroics behind for a few weeks are quickly scrapped when he begrudgingly agrees to help Nick Fury uncover the mystery of several elemental creature attacks, creating havoc across the continent.',
screenshots: [
'assets/images/1.PNG',
'assets/images/2.PNG',
'assets/images/3.PNG',
],
),
Movie(
imageUrl: 'assets/images/Star.PNG',
title: 'Star',
categories: 'Adventure, Family, Fantasy',
year: 2000,
country: 'US',
length: 100,
description:
'All Clara wants is a key - a one-of-a-kind key that will unlock a box that holds a priceless gift from her late mother. A golden thread, presented to her at godfather Drosselmeyer\'s annual holiday party, leads her to the coveted key-which promptly disappears into a strange and mysterious parallel world. It\'s there that Clara encounters a soldier named Phillip, a gang of mice and the regents who preside over three Realms: Land of Snowflakes, Land of Flowers, and Land of Sweets. Clara and Phillip must brave the ominous Fourth Realm, home to the tyrant Mother Ginger, to retrieve Clara\'s key and hopefully return harmony to the unstable world.',
screenshots: [
'assets/images/l1.PNG',
'assets/images/nl2.PNG',
'assets/images/kl3.PNG',
],
),
Movie(
imageUrl: 'assets/images/johnyjohny.PNG',
title: 'Johny',
categories: 'Adventure, Fantasy',
year: 2019,
country: 'ire',
length: 65,
description:
'Woody, Buzz Lightyear and the rest of the gang embark on a road trip with Bonnie and a new toy named Forky. The adventurous journey turns into an unexpected reunion as Woody\'s slight detour leads him to his long-lost friend Bo Peep. As Woody and Bo discuss the old days, they soon start to realize that they\'re two worlds apart when it comes to what they want from life as a toy.',
screenshots: [
'assets/images/johny.PNG',
'assets/images/johny.PNG',
'assets/images/johny.PNG',
],
),
];`
You get this error because you try to compare different types with each other; movies(List) and movies[0](a member of movies whose type is Movie) and they can not be equal never. For what reason you want to use "if" statement if you explain that, we may help you easier.
enter image description here
[ ][2]
these are two images showing my code , i want when the user click on the arrow-play button to take him to other page where the video is displayed depending on the list of movies

Sort a list in Prolog

The fact base stores exam schedule information in the form: exam ('group', 'subject', 'teacher', date). Write a program that allows you to select exam information for the group / teacher, sorting it by date.
So, I already know how to get data from base depending on what you want (by Group number or by teacher name):
exam('426-1', 'PROGRAMMING', 'John', 08-12-2019).
exam('426-1', 'MATH', 'John', 18-12-2019).
exam('426-3', 'ENG', 'Gabe', 16-12-2019).
exam('426-4', 'LITERATURE', 'Homer', 11-12-2019).
findByGroup(Number, Exams) :-
findall([A,B|C], exam(Number, A,B,C), Exams).
findByTeacher(Name, Exams) :-
findall([A,B|C], exam(A, B, Name,C), Exams).
Here's the input
findByGroup('426-1', X).
And here's the output
X = [['PROGRAMMING', 'John'|8-12-2019], ['MATH', 'John'|18-12-2019]]
But I have no idea how should I sort my output by date. For example, how can I sort the data by ascending of the date?
Example:
Before X = [['MATH', 'John'|18-12-2019], ['PROGRAMMING', 'John'|8-12-2019]]
After X = [['PROGRAMMING', 'John'|8-12-2019], ['MATH', 'John'|18-12-2019]]
There are a couple of things that need to be considered:
The date format needs to be in a format that sorts chronologically
The information for each exam item needs to be organized into a term that will sort based upon the date
For the date format, you are using a - functor with integer arguments. This is Ok. To make it sortable chronologically, the order needs to be year-month-day. You can either change your original data to be in that form, or translate to the sortable form before you do your sorting.
Regarding the exam data record, if you create a record formatted as a term with the date as the first argument, then sorting the records will sort by date. For example, any of the following terms will sort by date in Prolog:
exam(Date, Number, A, B)
[Date, Number, A, B]
...etc...
Now we apply this to your problem. Sorting can be done using setof/3 instead of findall/3 if your date is formatted in a sortable form:
% exam(Number, Class, Name, Date)
exam('426-1', 'PROGRAMMING', 'John', 2019-12-08).
exam('426-1', 'MATH', 'John', 2019-12-18).
exam('426-3', 'ENG', 'Gabe', 2019-12-16).
exam('426-4', 'LITERATURE', 'Homer', 2019-12-11).
findByGroup(Number, Exams) :-
setof([Date, Number, Class, Name], exam(Number, Class, Name, Date), Exams).
findByTeacher(Name, Exams) :-
setof([Date, Number, Class, Name], exam(Number, Class, Name, Date), Exams).
This will provide terms with attributes in a slightly different order: [Date, Number, Class, Name]. You can either just work with that, or you could easily change it:
reformat_exam_list([Y-M-D, Number, Class, Name], [Number, Class, Name, D-M-Y]).
And then call maplist(reformat_exam_list, Exams, ReformattedExams).
If you can't change the date format in your original facts, you can pre-process them as part of your setof/3 call.
reformat_sorted_exam(exam(Y-M-D, Number, Class, Name), exam(Number, Class, Name, D-M-Y)).
findByGroup(Number, Exams) :-
setof(exam(Y-M-D, Number, Class, Name), exam(Number, Class, Name, D-M-Y), ExamList),
maplist(reformat_sorted_exam, SortedExams, Exams).
Here I also used an exam structure instead of a list to represent an exam. You get the idea...

Retrieve data from database without printing

How do I retrieve data from the database to use it in a condition, but I don't want to print it the console.
Problem I am doing is to retrieve a child from a database whose parents age differ by 15 years.
This is the code I am using which works and prints the year of both parents.
family(person(_,_,date(_,_,Year1),_),
person(_,_,date(_,_,Year2),_),
[person(Name,Surname,_,_)|Y]), abs(Year1-Year2) >= 15.
Define a predicate rule (in a source file) using the query as its body. For example:
child_with_parents_age_gap(Gap, Name, Surname) :-
family(
person(_,_,date(_,_,Year1),_),
person(_,_,date(_,_,Year2),_),
[person(Name,Surname,_,_)| _]
),
abs(Year1-Year2) >= Gap.

How can I do a hash set of type object based on id’s or names?

How can I do a hash set of type object based on id’s or names? I’ve tried this…
var studentList= from sl in db.Assignments where sl.teacherId==id && sl.DayOfWeek==dayofweek select sl;
var newStudentList = new HashSet<Assignment>(studentList);
…but it doesn’t filter enough. For example I have some records that contain multiple entries.
Name Subject Date ID
John Math 6-12 7
John Math 6-18 7
Mary English 6-12 8
Mary English 6-18 8
Mary Math 6-12 8
John Math 6-27 7
John English 6-12 7
John English 6-18 7
John Art 6-12 7
John Art 6-18 7
I want to filter for no repetition and returns a list of entities that looks like this ignoring the date.
John Math 7
Mary English 8
Mary Math 8
John English 7
John Art 7
Can I use a HashSet to do this? If HashSet does not work, can you please suggest another way?
Thanks for any help!
If you can filter this out on the DB level, then just use Distinct.
If it's not possible, one simple solution is to implement Equals and GetHashCode on your object. HashSet will pick them up and use them for equality comparisons.
Another solution would be to use the following DistinctBy function:
public static IEnumerable<T> DistinctBy<T, TProp>(this IEnumerable<T> sequence, Func<T, TProp> selector, IEqualityComparer<TProp> equalityComparer = null)
{
var seen = new HashSet<TProp>(equalityComparer ?? EqualityComparer<TProp>.Default);
return sequence.Where(item => seen.Add(selector(item)));
}
and then use:
students.DistinctBy(s => new { s.Name, s.Subject, ... });
These two last solutions will only work on linq to objects.

Resources