sum of minterm vs product of maxterm - boolean-logic

Given the following Boolean expression of F(A,B,C): F(A,B,C) = A' + B + C'
Which of the following statements is/are true about the above expression?
(i) It is an SOP expression
(ii) It is a POS expression
(iii) It is a sum-of-minterms expression
(iv) It is a product-of-maxterms expression
The model answer for this question is i),ii) and iv)
My question is why is iii) not one of the answers? i drew the K-map and found out that its possible to derive such a sum-of-minters expression

A cluster of literals in a boolean expression forms a minterm or a maxterm only, if there are all literals (variables of the given function or their negation) included in it.
A minterm is a product of all literals of a function, a maxterm is a sum of all literals of a function.
In a K-map a minterm or a maxterm marks out only one cell. In a truth table a maxterm or a minterm matches only one row.
The following truth-table corresponds to the given function:
index | a | b | c || f(a,b,c) | term matching the row/K-map cell
-------|---|---|---||----------|----------------------------------
0 | 0 | 0 | 0 || 1 | minterm: m0 = (¬a⋅¬b⋅¬c)
1 | 0 | 0 | 1 || 1 | minterm: m1 = (¬a⋅¬b⋅c)
2 | 0 | 1 | 0 || 1 | minterm: m2 = (¬a⋅b⋅¬c)
3 | 0 | 1 | 1 || 1 | minterm: m3 = (¬a⋅b⋅c)
-------|---|---|---||----------|----------------------------------
4 | 1 | 0 | 0 || 1 | minterm: m4 = (a⋅¬b⋅¬c)
5 | 1 | 0 | 1 || 0 | MAXTERM: M5 = (¬a + b + ¬c)
6 | 1 | 1 | 0 || 1 | minterm: m6 = (a⋅b⋅¬c)
7 | 1 | 1 | 1 || 1 | minterm: m7 = (a⋅b⋅c)
There is only one maxterm present in the truth table (and your K-map) and the only maxterm determining the function's output as logical 0. It is a valid product-of-maxterms expression, even if there is only one. It is also the same boolean expression as the original one, so that is a valid product-of-maxterms expression too.
However, this is not a valid sum of minterms, because there is none:
f(a,b,c) = ∏(5) = M5 = (¬a + b + ¬c)
For the original expression to be also the sum of minterms, it would need to mark out every single true/one cell in your K-map separately like this:
f(a,b,c) = ∑(0,1,2,3,4,6,7) = m0 + m1 + m2 + m3 + m4 + m6 + m7 =
= (¬a⋅¬b⋅¬c)+(¬a⋅¬b⋅c)+(¬a⋅b⋅¬c)+(¬a⋅b⋅c)+(a⋅¬b⋅¬c)+(a⋅b⋅¬c)+(a⋅b⋅c)
As you can see, even if these two boolean expressions are equivalent to each other, the original one (on the left side of the equation) is not written as the sum-of-minterms expression (on the right side of the equation).
(¬a+b+¬c) = (¬a⋅¬b⋅¬c)+(¬a⋅¬b⋅c)+(¬a⋅b⋅¬c)+(¬a⋅b⋅c)+(a⋅¬b⋅¬c)+(a⋅b⋅¬c)+(a⋅b⋅c)
Just any product is not a minterm, so the original expression could be in the form of both the product of sum and the sum of products, but not the valid sum-of-minterms.
f(a,b,c) = (¬a + b + ¬c) = (¬a) + (b) + (¬c)
In the picture (created using latex) you can see the expression – it is the same in it's minimal DNF and minimal CNF – and the sum of minterms equivalent to it.

Related

Group rows by the same value in the field, while matching on partial value only

I have a table that has many rows (between a few 1000s to a few million).
I need my query to do the following:
group results by the same part of the value in the field;
order by the biggest group first.
The table has mostly values that have only some part are similar (and i.e. suffix would be different). Since the number of similar values is huge - I cannot predict all of them.
Here is i.e. my table:
+--------+-----------+------+
| Id | Uri | Run |
+--------+-----------+------+
| 15145 | select_123| Y |
| 15146 | select_345| Y |
| 15148 | delete_123| N |
| 15150 | select_234| Y |
| 15314 | delete_334| N |
| 15315 | copy_all | N |
| 15316 | merge_all | Y |
| 15317 | select_565| Y |
| 15318 | copy_all | Y |
| 15319 | delete_345| Y |
+--------+-----------+------+
What I would like to see, something like this (the Count part is desirable but not required):
+-----------+------+
| Uri | Count|
+-----------+------+
| select | 4 |
| delete | 3 |
| copy_all | 2 |
| merge_all| 1 |
+-----------+------+
If you're using MySQL 5.x, you can strip the trailing _ and digits from the Uri value using this expression:
LEFT(Uri, LENGTH(Uri) - LOCATE('_', REVERSE(Uri)))
Using a REGEXP test to see if the Uri ends in _ and some digits, we can then process the Uri according to that and then GROUP BY that value to get the counts:
SELECT CASE WHEN Uri REGEXP '_[0-9]+$' THEN LEFT(Uri, LENGTH(Uri) - LOCATE('_', REVERSE(Uri)))
ELSE Uri
END AS Uri2,
COUNT(*) AS Count
FROM data
GROUP BY Uri2
Output:
Uri2 Count
copy_all 2
delete 3
merge_all 1
select 4
Demo on SQLFiddle
The format of the string makes it uneasy to parse it with string functions.
If you are running MySQL 8.0, you can truncate the string with regexp_replace(), then group by and order by:
select regexp_replace(uri, '_\\d+$', '') new_uri, count(*) cnt
from mytable
group by new_uri
order by cnt desc
If you're using MySQL 8.x, you can use REGEXP_REPLACE() to remove the numeric suffixes from select_XXX and delete_XXX, then group by the result.
SELECT REGEXP_REPLACE(uri, '_[0-9]+$', '') AS new_uri, COUNT(*) as count
FROM yourTable
GROUP BY new_uri
You can do as below and create a view and using the case expression + substr find which are 'select' and 'delete'.
Following the view you can query it with the count/group_by.
WITH view_1 AS (
SELECT
CASE
WHEN substr(uri, 1, 6) = 'select' THEN
substr(uri, 1, 6)
WHEN substr(uri, 1, 6) = 'delete' THEN
substr(uri, 1, 6)
ELSE uri
END AS uri
FROM
your_table
)
SELECT
uri,
COUNT(uri) as "Count"
FROM
view_1
GROUP BY
uri
ORDER BY count(uri) DESC;
Output will be
delete 5
merge_all 4
select 3
copy_all 3

combining dataframes, and adding values of common elements

I have multiple data sets like this
data set 1
index| name | val|
1 | a | 1 |
2 | b | 0 |
3 | c | 3 |
data set 2
index| name | val|
1 | g | 4 |
2 | a | 2 |
3 | k | 3 |
4 | l | 2 |
I want to combine these data sets in such a way that if the both the data sets have a row with a common element name, in this example, "a", i want to have only a single row for the combined dataset, where the value is sum of that a and this a, in this case the combined row a would have a val of 3 (2+1). index number for elements does not matter. is there an effective way to do this in excel itself? I'm new to querying data, but im trying to learn. If i can do this in pandas(i'm trying to make myself familiar in this language) or sql, I will do so. My data sets are of different sizes
use:
df3 = df1.groupby('name').sum().add(df2.groupby('name').sum(), fill_value=0).reset_index()
df3['val'] = df3.fillna(0)[' val']+df3.fillna(0)['val']
df3 = df3.drop([' val'], axis=1)
print(df3)
Output:
name index val
0 a 3.0 3.0
1 b 2.0 0.0
2 c 3.0 3.0
3 g 1.0 4.0
4 k 3.0 3.0
5 l 4.0 2.0
IN Sql you can try below query:
select name,sum(val)
from
(select index,name,val from dataset1
union all
select index,name,val from dataset2) tmp
group by name
In Pandas:
df3=pd.concat([df1,df2],ignore_index=True)
df3.groupby(['name']).sum()

psql to csv file '-' becomes '-0'

I want to output the results from a psql query to a csv file. I have used the following approach
\o test.csv
SELECT myo_date, myo_maps_study, cbp_lvef, cbp_rvef, myx_ecg_posneg, myx_st, std_drugs, std_reason_comment FROM myo INNER JOIN studies ON (myo_std_uid = std_uid) LEFT OUTER JOIN cbp on (std_uid = cbp_std_uid) LEFT OUTER JOIN myx on (std_uid = myx_std_uid) WHERE myo_maps_study ~ 'MYO[0-9]*\$' AND std_reason_comment ~ 'AF' AND cbp_lvef is not null AND myx_st IS NOT NULL AND std_drugs IS NOT NULL ORDER by myo_date DESC LIMIT 500;
\q
The results on the query on its own is as follows
06/11/2013 | MYO134537 | 36.75000 | 29.00000 | - | 0.0 | ASPIRIN;BISOPROLOL;LISINOPRIL;METFORMIN;PPI;STATIN;FLUOXETINE;AMLODIPINE;GTN | CPOE;AF;T2DM;POSET
31/10/2013 | MYO130555 | 45.00000 | 36.25000 | - | 0.0 | DILTIAZEM;STATIN;LISINOPRIL;ASPIRIN;FRUSEMIDE;SALBUTAMOL;PARACETAMOL;AMOXICILLIN | TROP-VE; CP; AF; CTPA-VE; ANT T; INV; RF
23/10/2013 | MYO130538 | 18.75000 | 18.50000 | + | -1.0 | ASPIRIN;BISOPROLOL;RAMIPRIL | AF;MR;QLVFN;FAILED CARDIOVERSION
18/10/2013 | MYO134510 | 39.50000 | 32.25000 | - | 0.0 | ASPIRIN;STATIN;CO-CODAMOL;BISOPROLOL;GTN;PPI | PVD;AF
18/10/2013 | MYO130537 | 19.00000 | 18.00000 | - | 0.0 | STATIN;RAMIPRIL;AMLODIPINE;WARFARIN;(METOPROLOL-STOPPED FOR TEST) | TIA;AF;RF+++;ETINAP
However the csv file (opened in open office) looks like this
06/11/2013 MYO134537 36.75 29 -0 0 ASPIRIN;BISOPROLOL;LISINOPRIL;METFORMIN;PPI;STATIN;FLUOXETINE;AMLODIPINE;GTN CPOE;AF;T2DM;POSET
31/10/2013 MYO130555 45 36.25 -0 0 DILTIAZEM;STATIN;LISINOPRIL;ASPIRIN;FRUSEMIDE;SALBUTAMOL;PARACETAMOL;AMOXICILLIN TROP-VE; CP; AF; CTPA-VE; ANT T; INV; RF
23/10/2013 MYO130538 18.75 18.5 0 -1 ASPIRIN;BISOPROLOL;RAMIPRIL AF;MR;QLVFN;FAILED CARDIOVERSION
18/10/2013 MYO134510 39.5 32.25 -0 0 ASPIRIN;STATIN;CO-CODAMOL;BISOPROLOL;GTN;PPI PVD;AF
18/10/2013 MYO130537 19 18 -0 0 STATIN;RAMIPRIL;AMLODIPINE;WARFARIN;(METOPROLOL-STOPPED FOR TEST) TIA;AF;RF+++;ETINAP
The '-' signs have become -0 and '+' have become 0. For clarity, I would like to change these to N and P respectively.
Doing a more test.csv gives
06/11/2013,MYO134537,36.75,29,-0,0,ASPIRIN;BISOPROLOL;LISINOPRIL;METFORMIN;PPI;STATIN;FLUOXETINE;AMLODIPINE;GTN,CPOE;AF;T2DM;POSET,,
31/10/2013,MYO130555,45,36.25,-0,0,DILTIAZEM;STATIN;LISINOPRIL;ASPIRIN;FRUSEMIDE;SALBUTAMOL;PARACETAMOL;AMOXICILLIN,TROP-VE; CP; AF; CTPA-VE; ANT T; INV; RF,,
23/10/2013,MYO130538,18.75,18.5,0,-1,ASPIRIN;BISOPROLOL;RAMIPRIL,AF;MR;QLVFN;FAILED CARDIOVERSION,,
18/10/2013,MYO134510,39.5,32.25,-0,0,ASPIRIN;STATIN;CO-CODAMOL;BISOPROLOL;GTN;PPI,PVD;AF,,
18/10/2013,MYO130537,19,18,-0,0,STATIN;RAMIPRIL;AMLODIPINE;WARFARIN;(METOPROLOL-STOPPED FOR TEST),TIA;AF;RF+++;ETINAP,,
However, when I select the cell in open office the contents of -0 or 0 cells is always 0. This does not allow me to do a search a replace. I do not want to change these manually.
Can I force the + and - through using a psql command or can I use some other linux tool to change the -0 to N and 0 to P. I am using RHEL6.
Try using the decode function in place of the field name.
decode(myx_ecg_posneg,'-','N','+','P')
Update: Sorry, that's pl/sql. Try the case expression:
CASE myx_ecg_posneg
WHEN '-' THEN 'N'
WHEN '+' THEN 'P'
END

mysql - dynamic query depending on multiple grouped other values

In my application there are products and a product-variant-group which has a defined set of properties which a product of this group must declare and the combination of the properties is unique across that product-variant-group.
Example screen from amazon:
In the image the first select menu has all values obviously. The next select menu depends on the previously selected value, and so on.
Those defined group properties have a unique priority assigned to it which in the following derived table equals the property itself.
For a given property/priority and given list of of property/priority-value pairs. I want to retrieve its possible values.
The priorities of the value pairs must be smaller then the given priority.
public String[] getProductVariantGroupValues(int productVariantGroupId, int priority, Map<Integer, String> prevValues);
An example makes it much clearer:
I have an sql statement which lists all product-variant-group properties that related products have defined:
+---------+----------+-------- +
| product | priority | value |
+---------+----------+---------+
| 1 | 1 | Black |
| 1 | 2 | 38 |
| 1 | 3 | Dots |
| 2 | 1 | Black |
| 2 | 2 | 38 |
| 2 | 3 | Stripes |
| 3 | 1 | Yellow |
| 3 | 2 | 40 |
| 3 | 3 | Stripes |
+---------+----------+---------+
Other view for understanding *(priority is arbitrary just for understanding, with this view this would be trivial)*:
+---------+--------+--------+---------+
| product | value1 | value2 | value3 |
+---------+--------+--------+---------+
| 1 | Black | 38 | Dots |
| 2 | Black | 38 | Stripes |
| 3 | Yellow | 40 | Stripes |
+---------+---------------------------+
Call the above method with priority = 3 and prevValues = {(1, Black), (2, 38)} should result in following result array: {Dots, Stripes}.
If black is selected for property/priority 1 and 38 is selected for property/priority 2 the only possible following values for property/priority 3 are {Dots, Stripes}
The example is simplified and an arbitrary number of properties/priority should be supported. The query must be created dynamically to support arbitrary number of lower priority values.
Maybe I should just use the second table appraoch with a fixed set of properties which would make the unique constraint and this query very simple.
If I understand the question correctly, you have a value for priority 1 and for priority 2 and want to get all priority 3 values that match. The following query gets the products:
select product
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
To get the priority 3 values requires or a clever select statement (assuming priorities are not repeated for a product):
select product, max(case when priority = 3 then value end)
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
These queries are to give you an idea of how to construct the queries in your code. The generalization should be pretty straightforward.

SQL: Selecting columns based on column value from another table

I have the following tables:
UserPrivileges:
+--------+------+------+------+
| UserID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | 0 | 1 | 1 |
| 2 | 0 | 0 | 1 |
| 3 | 1 | 0 | 0 |
| 4 | 1 | 1 | 0 |
+--------+------+------+------+
Data:
+--------+------+------+------+
| DataID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | A | B | C |
| 2 | D | E | F |
| 3 | G | H | I |
| 4 | J | K | L |
+--------+------+------+------+
My question at its simplest form doesn't has anything to do with the Data table but I just explain it anyways so that I might be doing it the wrong way.
How would I select the Column names from UserPrivileges based on the value ? So that I can use the result in another query to select only those columns.
Something along these lines:
SELECT (COLUMNS_NAME_QUERY_FROM_UserPrivileges(UserID='#')) WHERE DataID = '#' FROM Data
Or I don't mind a better way to manage user Privileges for specific columns.
The answer depends upon your requirements for the result. Do you require a result with a consistent set of columns, regardless of user privs? If so, you could set the disallowed values to null (or some other special value) using a IF clause, e.g.,
SELECT IF (p.col1 = 0 THEN NULL ELSE d.col1) AS col1,
IF (p.col2 = 0 THEN NULL ELSE d.col2) AS col2,
IF (p.col3 = 0 THEN NULL ELSE d.col3) AS col3
FROM Data d,
UserPrivileges p
WHERE p.userId = '#'
AND d.DataId = '#'
Of course, the "special value" could be a problem, since you need a value that would never appear in the data. If you needed to know that difference between a null because the real value is null vs. null because it is a prohibited column then you can't use null.
Another approach would have you simple include the privilege indicator for each column appear in the result, and let your business logic use that to determine which values are visible to the user.
A very different approach would have the result set to contain only the allowed columns. In this case you'll need to build your sql statement dynamically. I don't know if you are doing this in a stored procedure or in a host language, but the basic idea is something like this:
string sqlCmd = "SELECT "
+ (SELECT (FIELDS_NAME_QUERY(UserID='#')
FROM USER_PRIVILEGES
WHERE userid='#')
+ FROM data d
execute sqlCmd
"execute" meaning whatever you have available to execute a string as a sql command.
more after clarification by OP:
Ok, you need sql function that returns a string that looks like "colname1, colname2, ...". The following resembles what it would look like in sql server. syntax
create function
FIELDS_NAME_QUERY (#userid int)
begin
select col1, col2, col3... INTO #col1priv, #col2priv, #col3priv FROM userPrivileges WHERE UserId = #UserId
declare #result varhcar(60)
set #result = ''
if (#col1priv = 1) #result = 'col1'
if (#col2priv = 1) #result = #result + ' ,col2'
if (#col3priv = 1) #result = #result + ' ,col3'
return #result
end
have not tried it, but something like this should work
SELECT (SHOW COLUMNS FROM table WHERE expr) FROM data WHERE DataID = '#'
Check this post for details - How can I get column names from a table in Oracle?
Let us know how you solve this...