Module:Formula

From MaRDI portal

Documentation for this module may be created at Module:Formula/doc

-- Required modules for SPARQL queries and HTML table generation
-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text") 

-- Main table to hold all functions
local p = {}

-- function to check whether the item has the MathModDB community tag
function p.hasMathModDB(frame)
    local entityId = frame.args[1] or mw.wikibase.getEntityIdForCurrentPage()
    if not entityId then
    	-- "" equivalent to false
        return ""
    end

    local entity = mw.wikibase.getEntity(entityId)
    if not entity or not entity.claims or not entity.claims.P1495 then
        -- "" equivalent to false
        return ""
    end

    for _, claim in pairs(entity.claims.P1495) do
        local value = claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value
        if value and value.id == "Q6534265" then
        	-- non empty ("") equivalent to true
            return true
        end
    end

	-- "" equivalent to false
    return ""
end



-- Function to get defining formulation with Quantities 
function p.extractDefiningFormulationWithQuantities(frame)
	
	local equation = mw.wikibase.getEntity()
	local equationID = entity and entity.id or nil
	
	-- Table to store formulations
    local formulations = {}
    -- Table to store quantity symbol and name id 
    local quantitySymbolNameIdPairs = {}
    
  
	-- P989 refers to property defining formula 
	local definingFormula = equation:getBestStatements('P989')
	if definingFormula and #definingFormula > 0 then
    	local value = definingFormula[1].mainsnak.datavalue.value
    	mathTag = frame:extensionTag{
	    	name = "math",
	        content = value
        }
	   table.insert(formulations, "| Defining Formula: " .. mathTag)
	end
   
    
    quantitySymbolNameIdPairs = p.extractQuantities(equationID)
    if type(quantitySymbolNameIdPairs) == "table" then
    	-- Accessing the stored pairs
		for i, pair in ipairs(quantitySymbolNameIdPairs) do
			local pairFirstValue = pair[1]
			local pairFirstValue = mw.text.decode(pairFirstValue or "")
			local quantitySymbolMathTag = frame:extensionTag{
				  name = "math",
            	  content = pairFirstValue
        		  }
        	-- Construct the Portal URL
        	local quantityId = pair[3]
        	local numericId = quantityId:sub(2)  -- remove "Q" to get "6674540"
        	
        	local quantity = mw.wikibase.getEntity(quantityId)
        	-- P31 referes to property instance of
        	local quantityStatement = quantity:getBestStatements('P31')[1]  -- Get the first (and only) statement
    		local instanceId = quantityStatement.mainsnak.datavalue.value.id
    		
    		
    		local urlRendered
			if instanceId == 'Q6481152' then
	    		urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
    		elseif instanceId == 'Q6534237' or instanceId ==  'Q6534245' then
        		urlRendered = "https://portal.mardi4nfdi.de/wiki/Quantity:" .. numericId
			end
        	
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(pair[2]))
        	
            table.insert(formulations, "| " .. quantitySymbolMathTag   ..  " represents "  .. labelWithUrl)
		end
		table.insert(formulations, "| " .. " " )
	else
		-- Error: extractQuantities did not return a table"
	end

		-- Construct the Wikitext table
    	local wikitextTable = [[
{| class="wikitable" style="table-layout: auto;"
]] .. table.concat(formulations, "\n|-\n") .. "\n|}"
    	return wikitextTable
  end

function p.extractQuantities(qid)
	-- Property ID for in defining formula 
    local pidInDefiningFormula  = "P983"
    -- Property ID for the (qualifier) symbol represents
    local pidSymbolRepresents = "P984"   

    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(qid)
    if not entity or not entity.claims[pidInDefiningFormula] then
        return "No formulation found"
    end
    
    
    local inDefiningFormulaClaims = entity.claims[pidInDefiningFormula]
    local count = 0
    -- Table to store pairs of quantity symbol and quantity name
    local quantitySymbolNameIdPairs = {}
	for _ in pairs(inDefiningFormulaClaims or {}) do
    	count = count + 1
    	-- Get the quantity symbol
    	local quantitySymbol = inDefiningFormulaClaims[count].mainsnak.datavalue.value
    	if not quantitySymbol then
        	return "No valid symbol found"
    	end
    	quantity = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.text
        quantityId = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.id
	    local quantityName = mw.wikibase.label(quantityId)
	    -- Insert pair into the table
	    table.insert(quantitySymbolNameIdPairs, {quantitySymbol, quantityName, quantityId})
    end
    return quantitySymbolNameIdPairs
end


-- Function to get specialized Research Problems
function p.getSpecializedFormulas(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1684: specialized by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label  
	WHERE {
		entityId: wdt:P1684 ?URL.
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")
	}
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local specializedFormulas = {}
    -- Get the number of specialized research fields
	local totalFormulas = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalFormulas  do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	table.insert(specializedFormulas, "| " .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(specializedFormulas, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get formula discretizations
function p.getDiscretizations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1656: discretized property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?DiscretizedURL ?DiscretizedLabel
	WHERE {
		entityId: p:P1656 ?statement.
		?statement ps:P1656 ?DiscretizedURL.
		?DiscretizedURL rdfs:label ?DiscretizedLabel.
		FILTER(LANG(?DiscretizedLabel) = "en")
	}
	ORDER BY ?DiscretizedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local discretizations = {}
    -- Get the number of discretizations
	local totalDiscretizations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalDiscretizations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.DiscretizedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.DiscretizedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.DiscretizedLabel.value
        	local url = item.DiscretizedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(discretizations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(discretizations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get formula approximations
function p.getApproximations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1655: approximated by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?ApproximatedURL ?ApproximatedLabel
	WHERE {
		entityId: p:P1655 ?statement.
		?statement ps:P1655 ?ApproximatedURL.
		?ApproximatedURL rdfs:label ?ApproximatedLabel.
		FILTER(LANG(?ApproximatedLabel) = "en")
	}
	ORDER BY ?ApproximatedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local approximations = {}
    -- Get the number of discretizations
	local totalApproximations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalApproximations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.ApproximatedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.ApproximatedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.ApproximatedLabel.value
        	local url = item.ApproximatedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(approximations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(approximations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get similar formulas
function p.getSimilar(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1691: approximated by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?SimilarURL ?SimilarLabel
	WHERE {
		entityId: p:P1691 ?statement.
		?statement ps:P1691 ?SimilarURL.
		?SimilarURL rdfs:label ?SimilarLabel.
		FILTER(LANG(?SimilarLabel) = "en")
	}
	ORDER BY ?SimilarLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local similar = {}
    -- Get the number of similar expressions
	local totalSimilar = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSimilar  do
    	local item = jsonResults.results.bindings[index]
    	if not item.SimilarLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.SimilarURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.SimilarLabel.value
        	local url = item.SimilarURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(similar, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(similar, "\n|-\n") .. "\n|}"
	return wikitextTable

end

return p